Spec-Zone.ru › TypeScript 5.1

Картированные типы

Когда вы не хотите повторяться, иногда тип должен основываться на другом типе.

Картированные типы строятся на синтаксисе для индексных подписей, которые используются для объявления типов свойств, которые не были объявлены заранее:

type OnlyBoolsAndHorses = {
  [key: string]: boolean | Horse;
};
 
const conforms: OnlyBoolsAndHorses = {
  del: true,
  rodney: false,
};

Картированный тип — это обобщённый тип, который использует объединение PropertyKey (часто создаваемое через keyof) для итерации по ключам, чтобы создать тип:

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};

В этом примере, OptionsFlags возьмёт все свойства из типа Type и изменит их значения на булевы.

type Features = {
  darkMode: () => void;
  newUserProfile: () => void;
};
 
type FeatureOptions = OptionsFlags<Features>;

Модификаторы картирования

Существуют два дополнительных модификатора, которые могут быть применены во время картирования: readonly и ?, которые влияют на изменяемость и опциональность соответственно.

Вы можете удалить или добавить эти модификаторы, добавив префикс - или +. Если вы не добавите префикс, то + считается по умолчанию.

// Removes 'readonly' attributes from a type's properties
type CreateMutable<Type> = {
  -readonly [Property in keyof Type]: Type[Property];
};
 
type LockedAccount = {
  readonly id: string;
  readonly name: string;
};
 
type UnlockedAccount = CreateMutable<LockedAccount>;
// Removes 'optional' attributes from a type's properties
type Concrete<Type> = {
  [Property in keyof Type]-?: Type[Property];
};
 
type MaybeUser = {
  id: string;
  name?: string;
  age?: number;
};
 
type User = Concrete<MaybeUser>;

Переименование ключей через as

В TypeScript 4.1 и выше вы можете переименовать ключи в картированных типах с помощью as в картированном типе:

type MappedTypeWithNewProperties<Type> = {
    [Properties in keyof Type as NewKeyType]: Type[Properties]
}

Вы можете использовать такие возможности, как шаблонные литеральные типы, чтобы создавать новые имена свойств из предыдущих:

type Getters<Type> = {
    [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};
 
interface Person {
    name: string;
    age: number;
    location: string;
}
 
type LazyPerson = Getters<Person>;

Вы можете отфильтровать ключи, создав never с помощью условного типа:

// Remove the 'kind' property
type RemoveKindField<Type> = {
    [Property in keyof Type as Exclude<Property, "kind">]: Type[Property]
};
 
interface Circle {
    kind: "circle";
    radius: number;
}
 
type KindlessCircle = RemoveKindField<Circle>;

Вы можете применять картирование к произвольным объединениям, а не только к объединениям string | number | symbol, но к объединениям любого типа:

type EventConfig<Events extends { kind: string }> = {
    [E in Events as E["kind"]]: (event: E) => void;
}
 
type SquareEvent = { kind: "square", x: number, y: number };
type CircleEvent = { kind: "circle", radius: number };
 
type Config = EventConfig<SquareEvent | CircleEvent>

Дальнейшее изучение

Картированные типы хорошо работают с другими функциями в этом разделе манипуляции типами, например, вот картированный тип, использующий условный тип, который возвращает либо true, либо false, в зависимости от того, имеет ли объект свойство pii, установленное в литерал true:

type ExtractPII<Type> = {
  [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
};
 
type DBFields = {
  id: { format: "incrementing" };
  name: { type: string; pii: true };
};
 
type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;

© 2012-2024 Microsoft
Licensed under the Apache License, Version 2.0.
https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API