angular - Typescript (จริง ๆ) ปฏิบัติตามหลักเกณฑ์การตั้งชื่อสำหรับประเภทที่มีพารามิเตอร์ (T, U, V, W) ใน Generics หรือไม่?
ฉันไม่แน่ใจเลยว่าใน TS เราปฏิบัติตามหลักการตั้งชื่อประเภทที่มีพารามิเตอร์แบบนี้เหมือนกับ C++/Java หรือหลายภาษาอื่น ๆ (T,U,V,W) หรือไม่
ฉันเห็นหลายครั้งเกี่ยวกับการใช้งานแบบผสมของแนวปฏิบัติประเภทที่มีพารามิเตอร์ใน TS ตัวอย่างเช่น ในบันทึกการอัปเดตของ TS 2.8:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
ทำไมถึงเป็น R ไม่ใช่ U?
จากนั้น ในตัวอย่างถัดไป:
type Unpacked<T> = T extends (infer U)[]
? U
: T extends (...args: any[]) => infer U
? U
: T extends Promise<infer U>
? U
: T;
ทำไมถึงเป็น U ไม่ใช่ R?
ตัวอย่างอีกตัวอย่างหนึ่ง ในบล็อกโค้ดเดียวกันของโค้ดที่อยู่ด้านบน:
type T0 = Unpacked<string>; // string
type T1 = Unpacked<string[]>; // string
type T2 = Unpacked<() => string>; // string
type T3 = Unpacked<Promise<string>>; // string
type T4 = Unpacked<Promise<string>[]>; // Promise<string>
type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string
แต่ในซอร์สโค้ด TS:
// We represent tuple types as type references to synthesized generic interface types created by
// this function. The types are of the form:
//
// interface Tuple<T0, T1, T2, ...> extends Array<T0 | T1 | T2 | ...> { 0: T0, 1: T1, 2: T2, ... }
คำถามด้านบนเป็นเพียงตัวอย่างเพื่อชี้ให้เห็น คุณไม่จำเป็นต้องตอบพวกมัน ฉันสามารถเพิ่มตัวอย่างอื่นที่ U ถูกปฏิบัติในบางครั้งเหมือนชนิดการคืนค่า และบางครั้งก็แค่เป็นชนิดที่สอง
คำถามที่แท้จริงของฉันคือ: เรากำลังปฏิบัติตามมาตรฐานของ Java Generic Types สำหรับ TS Generics จริง ๆ หรือไม่? ถ้าไม่ TS ปฏิบัติตามมาตรฐานประเภทใดสำหรับ Generics? มีมาตรฐานประเภทที่แตกต่างกันกี่แบบที่อยู่ร่วมกันใน TS (นอกเหนือจากที่ชัดเจนคือ PascalCase สำหรับชื่อ Type และ camelCase สำหรับคุณสมบัติ/วิธีของ type)?
คำตอบ #1
(ส่วนใหญ่จากความคิดเห็น)
สิ่งที่ใกล้เคียงที่สุดที่ผมสามารถจินตนาการได้ในการตอบเรื่องนี้ในลักษณะที่ไม่ใช่เพียงความคิดเห็นของผมคือการอ้างถึงเอกสารบางอย่างที่อธิบายว่า "แนวทางการตั้งชื่อพารามิเตอร์ชนิดใน TypeScript" คืออะไร และเปรียบเทียบกับเอกสารสอน Java Generics ที่คุณลิงก์มา
ถ้าเป็นเช่นนั้น ท่าทีอย่างเป็นทางการของทีมออกแบบ TypeScript ต่อเรื่องนี้ดูเหมือนจะเป็น "เราไม่ได้ตั้งใจจะบังคับใช้ข้อกำหนดใด ๆ เหล่านี้กับผู้อื่น" หรือ "ไม่มีข้อกำหนดการตั้งชื่อที่เป็นมาตรฐานใน TS" ดูได้ที่ microsoft/TypeScript#6168 และ microsoft/TypeScript#878 โดยเฉพาะความคิดเห็นนี้:
โดยทั่วไปแล้ว เราไม่ได้สนใจที่จะตัดสินเรื่องสไตล์ให้กับผู้คน การกล่าวว่ามีสไตล์ที่ได้รับการยอมรับเพียงหนึ่งเดียวสำหรับ TS นั้นขัดแย้งกับปรัชญาของเราที่เรามีอยู่เพื่อให้ชนิดสำหรับ JS ไม่ว่าคุณจะเขียนมันอย่างไร (แน่นอน ภายในขอบเขตที่เหมาะสม 😉)
นอกจากนี้ยังมีกฎ naming-convention ของ ESLint และกฎ naming-convention ของ TSLint ซึ่งสามารถทำให้เป็นไปได้ในการบังคับใช้ข้อตกลงการตั้งชื่อพารามิเตอร์ประเภทในฐานรหัสที่ตรวจสอบด้วยลินเตอร์ แต่ดูเหมือนไม่ทำโดยค่าเริ่มต้น ดังนั้นไม่มีข้อตกลงใดที่ดูเหมือนจะเป็นทางการพอที่จะถูกบังคับใช้โดยค่าเริ่มต้น
เพื่อการเปรียบเทียบ ลองมาดูส่วนที่เกี่ยวข้องจากเอกสารสอน Java Generics ที่คุณลิงก์มา:
หลักเกณฑ์การตั้งชื่อพารามิเตอร์ชนิด
ตามธรรมเนียม ชื่อพารามิเตอร์ประเภทมักเป็นตัวอักษรตัวเดียวและเป็นตัวพิมพ์ใหญ่ ซึ่งตรงข้ามอย่างชัดเจนกับแนวปฏิบัติการตั้งชื่อตัวแปรที่คุณรู้จักอยู่แล้ว และด้วยเหตุผลที่ดี: หากไม่มีธรรมเนียมนี้ จะเป็นเรื่องยากที่จะบอกความแตกต่างระหว่างตัวแปรประเภทกับชื่อคลาสหรืออินเทอร์เฟซปกติ
ชื่อพารามิเตอร์ประเภทที่ใช้กันมากที่สุดคือ:
- E - อิลิเมนต์ (ใช้กันอย่างแพร่หลายโดย Java Collections Framework)
- K - กุญแจ
- N - ตัวเลข
- T - ประเภท
- V - ค่า
- S, U, V เป็นต้น - ประเภทที่ 2, 3, 4
คุณจะเห็นชื่่อเหล่านี้ถูกใช้ตลอด API ของ Java SE และส่วนที่เหลือของบทเรียนนี้
โปรดทราบว่ารายการแบบลำดับที่ระบุข้างต้นถูกอธิบายว่าเป็น "ชื่อพารามิเตอร์ประเภทที่ใช้บ่อยที่สุด" และไม่ใช่ "ชื่อพารามิเตอร์ประเภทที่อนุญาตเพียงอย่างเดียว"; นี่เป็นรายการตัวอย่างและดังนั้นจึงเป็น การบรรยาย และไม่ใช่ การกำหนด.
ส่วนที่เกี่ยวกับการเลือก "ตัวอักษรเดี่ยว ตัวพิมพ์ใหญ่" นั้น ใกล้เคียง กับคำแนะนำ: ตัวอักษรพิมพ์ใหญ่มักจะแยกชื่อ ชนิด ออกจากชื่อ ตัวแปร และชื่อชนิดที่เป็นตัวอักษรตัวเดียวมักจะแยก พารามิเตอร์ชนิด ออกจาก ชนิดเฉพาะ อย่างเช่นคลาสหรืออินเทอร์เฟซ แต่ฉันก็ได้รับความรู้สึกเดียวกันว่านี่ไม่ใช่คำสั่งจากเบื้องบนมากนัก แต่เป็นการสังเกตเกี่ยวกับแนวปฏิบัติทั่วไป
ดังนั้นเราจึงอาจหยุดเพียงแค่นั้นและกล่าวว่า "ไม่มีแนวทางการตั้งชื่อพารามิเตอร์ประเภทอย่างเป็นทางการหรือเป็นมาตรฐานในทั้ง TypeScript หรือ Java และแนวทางที่ไม่เป็นทางการนั้นขึ้นอยู่กับความคิดเห็น"
แต่เพื่อความพยายามในการสรุปสิ่งที่ผม คิดว่า ประเพณีที่ไม่เป็นทางการใน TypeScript จริงๆ เป็น อย่างไร ผมจะพูดต่อ โปรดจำไว้ว่า นี่เป็นความคิดเห็นของผม และคนอื่นอาจไม่เห็นด้วยได้
ฉันคงจะบอกว่าข้อกำหนดการตั้งชื่อของ Java ที่ได้กล่าวมาข้างต้นสอดคล้องอย่างใกล้ชิดกับสิ่งที่ฉันพิจารณาว่าเป็นข้อกำหนดการตั้งชื่อที่ใช้กันทั่วไปสำหรับพารามิเตอร์ชนิดเจเนอริกของ TypeScript: ใช้ตัวอักษรตัวใหญ่เพียงตัวเดียว ซึ่งสอดคล้องกับตัวอักษรแรกของสิ่งที่มันแทน เช่น:
Tหมายถึง "type" ซึ่งเป็นชื่อพารามิเตอร์ประเภทที่ทั่วไปที่สุดและดังนั้นจึงเป็นชื่อที่ใช้กันมากที่สุดKสำหรับ "key" หรือPสำหรับ "property" ทั้งคู่มีแนวโน้มที่จะถูกจำกัดโดยPropertyKeyหรือkeyof Tหรือkeyof SomeInterfaceหรือkeyof SomeClass;Vสำหรับ "ค่า" ซึ่งมักใช้เป็นคู่กับKสำหรับ "กุญแจ"Aสำหรับ "arguments" และRสำหรับ "return" ซึ่งสอดคล้องกับรายการพารามิเตอร์ที่เหลือและประเภทการคืนค่าของลายเซ็นฟังก์ชันตามลำดับ เช่น(...args: A) => R;Nสำหรับ "number",Sสำหรับ "string",Bสำหรับ "boolean", สำหรับพารามิเตอร์ประเภทที่ถูกจำกัดโดยประเภทพื้นฐาน;
หรือบางลำดับของประเภทที่เกี่ยวข้อง เช่น:
T,U,V,Wเป็นต้น เริ่มต้นด้วยTสำหรับ "type" แล้วจึงไล่ตามตัวอักษรเมื่อจำเป็นต้องใช้ชนิดเพิ่ม โดยต้องจำไว้ว่าคุณสามารถได้เพียงไม่กี่ชนิดด้วยวิธีนี้A,B,C,Dฯลฯ เริ่มจากตัวอักษรแรกของตัวอักษรภาษาอังกฤษเมื่อคุณคาดว่าจะใช้พารามิเตอร์ชนิดจำนวนมากและคุณยังไม่ได้ใช้พารามิเตอร์ชนิดสำหรับสิ่งอื่น
ข้อตกลงดังกล่าวไม่ถือเป็นข้อบังคับเด็ดขาด และมักจะถูกปรับตามความจำเป็นเพื่อหลีกเลี่ยงความกำกวมหรือความสับสนอื่น ๆ หากคุณต้องการพารามิเตอร์ชนิดมากกว่าที่สามารถได้จากด้านบนโดยไม่เกิดการชนกันของชื่อ อาจจะต้องเพิ่มตัวอักษรเข้าไปในชื่อ:
T0,T1,T2,T3เป็นต้น การต่อท้ายตัวเลขเพื่อให้ได้ลำดับของประเภทที่เกี่ยวข้อง;KT,KU,KV: การเติมหน้าKสำหรับ "คีย์ของ"T,UและVตามลำดับ;
มันอยู่ห่างจากสิ่งที่ฉันถือว่าธรรมดา แต่ก็ยังพอพบได้บ่อยพอที่จะเขียนชื่อสั้นๆ แบบ UpperCamelCase เพื่อให้สื่อความหมายของประเภทที่แทนค่าได้ชัดเจนขึ้น โดยมีข้อเสียคือมันอาจเริ่มสับสนกับประเภทเฉพาะเจาะจงและไม่ใช่พารามิเตอร์ประเภท:
คีย์,ค่า,คุณสมบัติ,อาร์กิวเมนต์,ผลลัพธ์,ประเภท,นี้
สิ่งต่อไปนี้เป็นสิ่งที่ไม่ธรรมดา (จำไว้ว่า นี่คือความคิดเห็นของฉัน!) และควรหลีกเลี่ยงเว้นแต่จะมีเหตุผลพิเศษที่จำเป็นมากในการทำเช่นนั้น:
- ชื่อยาวที่ดูเหมือนชื่ออินเทอร์เฟซหรือคลาส เช่น
InputTypeหรือProperties; - การใส่ตัวอักษรใหญ่
Tไว้หน้าชื่อประเภทที่ยาวขึ้น เช่นTNotRecommended; - ชื่อที่เริ่มต้นด้วยตัวอักษรเล็ก เช่น
tหรือuหรือmyType;