Kodokon kodokon.com

Mapped type และ key remapping: การแปลงรูป type

เข้าใจว่า homomorphic mapped type รักษา modifier ไว้อย่างไร และ clause as เปลี่ยนชื่อหรือกรอง key อย่างไร

8 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

Mapped type วนซ้ำบนชุดของ key เพื่อผลิต object type ใหม่ รูปแบบ [K in keyof T] เรียกว่า homomorphic: คอมไพเลอร์รู้ว่าโครงสร้างมาจาก T และคัดลอก modifier readonly และ ? ของแต่ละ property เดิมมาโดยอัตโนมัติ คำนำหน้า + และ - ให้คุณเพิ่มหรือลบ modifier เหล่านี้ได้อย่างชัดเจน: นี่คือกลไกภายในที่อยู่เบื้องหลัง Partial, Required และ Readonly อย่างแท้จริง

TYPESCRIPT
type Mutable<T> = {
  -readonly [K in keyof T]-?: T[K];
};

interface Config {
  readonly host?: string;
  readonly port?: number;
}

type Draft = Mutable<Config>;
// { host: string; port: number }
คำนำหน้า - ลบ readonly และความ optional

ตั้งแต่ TypeScript 4.1 clause as เปิดใช้งาน key remapping: แต่ละ key สามารถถูกเปลี่ยนชื่อได้ทันที โดยทั่วไปผ่าน template literal type และหาก clause นั้นผลิต never key จะถูก ลบ ออกจากผลลัพธ์ไปเลย: นี่คือกลไกกรอง property อย่างเป็นทางการ สังเกต & string ในตัวอย่าง: keyof T อาจมี key ที่เป็น symbol หรือ number ซึ่งเข้ากันไม่ได้กับ template literal

TYPESCRIPT
type Getters<T> = {
  [K in keyof T & string as `get${Capitalize<K>}`]:
    () => T[K];
};

interface User { name: string; age: number }
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }

type OnlyMethods<T> = {
  [K in keyof T as
    T[K] extends (...args: never[]) => unknown
      ? K : never]: T[K];
};
เปลี่ยนชื่อด้วย as, กรองด้วยการผลิต never

มีจุดละเอียดอ่อนในสเปกที่มักถูกมองข้าม: เมื่อนำไปใช้กับ array หรือ tuple, homomorphic mapped type จะ ไม่ ผลิต object ที่มี key 0, 1 และ length คอมไพเลอร์รักษาธรรมชาติของ type ไว้: มันแปลงสมาชิกและคงรูปทรงของ array หรือ tuple ไว้ นี่คือสิ่งที่ทำให้ Readonly<[number, string]> ยังคงเป็น tuple การรักษานี้จะหายไปทันทีที่ mapped type ไม่เป็น homomorphic อีกต่อไป เช่นกรณี [P in K] ที่ K เป็น union ของ key แบบใดก็ได้

TYPESCRIPT
type Immutable<T> = {
  readonly [K in keyof T]: T[K];
};

type Pair = Immutable<[number, string]>;
// readonly [number, string]: the tuple survives

type List = Immutable<string[]>;
// readonly string[]
homomorphic mapped type เคารพ array และ tuple

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. ในการทำ key remapping จะเกิดอะไรขึ้นเมื่อ clause as ผลิต never ให้กับ key หนึ่ง?
    • property ได้ type เป็น never
    • key ถูกลบออกจาก type ผลลัพธ์
    • คอมไพเลอร์แจ้ง error
  2. { readonly [K in keyof T]: T[K] } ผลิตอะไรเมื่อนำไปใช้กับ tuple [number, string]?
    • object ที่มี key 0, 1 และ length
    • readonly [number, string]
    • readonly (number | string)[]
    • error ของการคอมไพล์
  3. modifier -? ใน mapped type มีผลอย่างไร?
    • ทำให้ property เป็น optional
    • ลบความ optional และ undefined ที่มันนำเข้ามา
    • ลบ modifier readonly
    • ลบ property ออกจาก type