เข้าใจการแก้ปัญหา overload, pseudo-parameter this และกฎ variance ที่ควบคุมการกำหนดค่าได้ (assignability) ของฟังก์ชัน
เปิดบทเรียนนี้ใน Kodokonฟังก์ชันแบบ overload เปิดเผยรายการ signature สาธารณะตามด้วย signature ของ implementation เพียงตัวเดียว จุดสำคัญในสเปก: ตัวหลังนั้น มองไม่เห็นจากภายนอก; เรียกใช้ได้เฉพาะ overload ที่ประกาศไว้เท่านั้น การแก้ปัญหาจะไล่ไปตาม signature จากบนลงล่าง และเก็บตัวแรกที่เข้ากันได้: จงวาง signature ที่เฉพาะเจาะจงที่สุดไว้ก่อนเสมอ ไม่เช่นนั้นมันจะไม่มีวันถูกเลือก
function parse(input: string): number;
function parse(input: string[]): number[];
function parse(input: string | string[]) {
return Array.isArray(input)
? input.map((s) => s.length)
: input.length;
}
const single = parse("abc"); // number
const many = parse(["a", "bb"]); // number[]TypeScript ให้คุณประกาศ pseudo-parameter this ในตำแหน่งแรกได้ มันถูก ลบทิ้งทั้งหมด จาก JavaScript ที่ปล่อยออกมา: มันเป็นข้อจำกัดแบบ static ล้วน ๆ บนบริบทการเรียก (call context) ซึ่งจะถูกตรวจสอบเมื่อเปิดใช้งาน noImplicitThis ยูทิลิตี ThisParameterType และ OmitThisParameter ให้คุณสกัดหรือลบมันออกได้ ซึ่งจำเป็นอย่างยิ่งสำหรับการกำหนด type ให้กับฟังก์ชันที่ตั้งใจจะใช้กับ call, apply หรือ bind
function greet(this: { name: string }, msg: string) {
return `${msg}, ${this.name}`;
}
type Ctx = ThisParameterType<typeof greet>;
// { name: string }
type Fn = OmitThisParameter<typeof greet>;
// (msg: string) => string
const user = { name: "Ada", greet };
user.greet("Hello"); // "Hello, Ada"
// greet("Hi"); // error: missing this contextVariance อธิบายว่าความสามารถในการกำหนดค่า (assignability) ส่งผ่านตัวสร้าง type (type constructor) อย่างไร สำหรับฟังก์ชัน return type เป็น covariant และเมื่อเปิด strictFunctionTypes พารามิเตอร์เป็น contravariant: ฟังก์ชันที่รับ type กว้างกว่าสามารถแทนที่ฟังก์ชันที่รับ type แคบกว่าได้ แต่ไม่ใช่ในทางกลับกัน มีข้อยกเว้นที่จงใจอย่างหนึ่ง: พารามิเตอร์ของ method ที่ประกาศด้วยไวยากรณ์แบบย่อยังคงเป็น bivariant ซึ่งเป็นการประนีประนอมเชิงประวัติศาสตร์ ที่ถ้าไม่มีมัน Array<Dog> ก็จะกำหนดค่าให้ Array<Animal> ไม่ได้ ตั้งแต่ 4.7 คุณสามารถระบุ variance ที่คาดหวังด้วย in และ out เช่น interface Producer<out T> และคอมไพเลอร์จะตรวจสอบมัน
interface Animal { name: string }
interface Dog extends Animal { bark(): void }
declare let f: (a: Dog) => void;
declare let g: (a: Animal) => void;
f = g; // OK: g accepts a wider type, that is safe
// g = f; // error with strictFunctionTypes
interface Sink { accept(a: Animal): void }
interface DogSink { accept(a: Dog): void }
declare let s: Sink;
declare let d: DogSink;
d = s; s = d; // both compile: bivariance!this ของฟังก์ชันใน JavaScript ที่ปล่อยออกมา?