TypeScript / Mapped Types

Mapped Types

Partial, Required, Pick, Omit зэрэг utility types-ийн "дотор" яг юу болж байдагыг мэдэх үү? Тэдгээр бүгд mapped type дээр суурилдаг. Mapped type нь байгаа төрлийн бүх property-г тойрч гарч, тус бүрт хувиргалт хийх зориулалттай.

Mapped type-ийн синтакс

typescript
// Үндсэн синтакс
type Хувиргасан<T> = {
  [K in keyof T]: T[K];
};
  • K — property-ийн нэр (түлхүүр)
  • keyof T — T-ийн бүх property нэрүүдийн union
  • T[K] — тухайн property-ийн төрөл

Энэ нь for...in давталттай маш төстэй боловч төрлийн систем дотор ажиллана:

typescript
interface Хэрэглэгч {
  нэр: string;
  нас: number;
  идэвхтэй: boolean;
}

// Бүх property-г string болгох хувиргалт
type БүгдМөр<T> = {
  [K in keyof T]: string;
};

type МөрХэрэглэгч = БүгдМөр<Хэрэглэгч>;
// { нэр: string; нас: string; идэвхтэй: string }

? ба readonly нэмэх/хасах

Mapped type-д ? ба readonly-г нэмж эсвэл хасаж болно:

typescript
interface Бүтээгдэхүүн {
  нэр: string;
  үнэ: number;
  тайлбар: string;
}

// Бүх property optional болгох — Partial-ийн хэрэгжилт яг ингэж ажилладаг
type МөрөнPartial<T> = {
  [K in keyof T]?: T[K];
};

// Бүх property readonly болгох
type БүгдReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

// ? хасах — Required-ийн хэрэгжилт
type МөрөнRequired<T> = {
  [K in keyof T]-?: T[K];
};

// readonly хасах
type МутабельТөрөл<T> = {
  -readonly [K in keyof T]: T[K];
};

-? гэдэг нь "optional тэмдгийг хас" гэсэн утгатай. TypeScript-ийн суурилсан Required<T> яг энэ аргаар бичигдсэн.

Төрлийг хувиргах mapped type

Property-ийн утгын төрлийг өөрчилж болно:

typescript
// Бүх утгыг Promise болгох
type Амлалт<T> = {
  [K in keyof T]: Promise<T[K]>;
};

// Бүх утгыг функц болгох
type Геттер<T> = {
  [K in keyof T]: () => T[K];
};

interface Тохиргоо {
  хост: string;
  порт: number;
  отладка: boolean;
}

type ТохиргооГеттер = Геттер<Тохиргоо>;
// {
//   хост: () => string;
//   порт: () => number;
//   отладка: () => boolean;
// }

as — property нэрийг хувиргах

TypeScript 4.1-с эхлэн as ашиглан property нэрийг мөн өөрчилж болно:

typescript
// Бүх property-д "авах_" угтвар нэмэх
type УгтвартайГеттер<T> = {
  [K in keyof T as `авах_${string & K}`]: () => T[K];
};

interface Хэрэглэгч {
  нэр: string;
  нас: number;
}

type ХэрэглэгчГеттер = УгтвартайГеттер<Хэрэглэгч>;
// {
//   авах_нэр: () => string;
//   авах_нас: () => number;
// }

Бодит жишээ: form validation объект

typescript
interface БүртгэлийнФорм {
  нэр: string;
  имэйл: string;
  нууц_үг: string;
  нас: number;
}

// Тус бүр талбарт алдааны мессеж хадгалах
type АлдааныТөлөв<T> = {
  [K in keyof T]: string | null;
};

type БүртгэлийнАлдаа = АлдааныТөлөв<БүртгэлийнФорм>;
// {
//   нэр: string | null;
//   имэйл: string | null;
//   нууц_үг: string | null;
//   нас: string | null;
// }

const алдаанууд: БүртгэлийнАлдаа = {
  нэр: null,
  имэйл: "Имэйл буруу форматтай байна",
  нууц_үг: "Нууц үг хэт богино байна",
  нас: null,
};

Mapped type нь нэг удаа тодорхойлоод, дурын interface-д хэрэглэж болох хэрэглүүр болдог. Form validation, API хариу зохицуулалт, өгөгдлийн хувиргалт зэрэг олон газар ашиглагддаг TypeScript-ийн хамгийн хүчирхэг онцлогуудын нэг.

Дараагийн хичээлд:

Conditional Types — T extends U ? X : Y синтакс ашиглан нөхцлөөс хамааран өөр өөр төрөл буцаадаг нарийн хэрэглүүрийг сурна.