DevGang
Авторизоваться

12 обязательных типов Utility в TypeScript с использованием и примерами

Внедрение TypeScript и его возможностей статической типизации оказало глубокое влияние на опыт разработчиков в мире JavaScript, сделав его теперь отраслевым стандартом для большинства крупномасштабных баз кода.

Однако ценность TypeScript не ограничивается статической типизацией. Он демонстрирует свое мастерство посредством набора нескольких типов утилит — предопределенных конструкций, которые позволяют разработчикам плавно изменять и использовать существующие типы: отPartialдля создания дополнительных свойств доReturnTypeдля вывода результатов функции, оптимизации сложных манипуляций с типами, экономя разработчикам время и умственные способности.

В этой статье мы поговорим о 12 недооцененных типах утилит, которые вам следует чаще использовать в своей кодовой базе. Эти типы утилит TypeScript подобны инструментам в вашем наборе инструментов для кодирования, каждый из которых служит уникальной цели, помогая вам формировать свой код с точностью и ясностью.

Оглавление

Типы манипуляций с объектами

  • Partial
  • Required
  • Readonly
  • Mutable
  • Pick
  • Record
  • Omit

Типы манипуляций с объединением

  • Exclude
  • NonNullable
  • Extract

Типы функций

  • Parameters
  • Return Type
  • Awaited

Примечание об интерфейсах и типах

В этой статье мы будем использовать как интерфейсы, так и типы.

В TypeScript выбор между использованием типов и интерфейсов зависит от конкретного сценария. Интерфейсы подходят для описания формы объектов, определения их свойств, методов и событий. С другой стороны, типы более универсальны, позволяя определять псевдонимы примитивных типов, кортежи, объединения и работать с функциями, сложными типами и отображаемыми типами. В конечном итоге выбор между типами и интерфейсами зависит от конкретного варианта использования и решения разработчика.

1. Partial

Partial позволяет создать тип, в котором все свойства типа T станут необязательными. Это все равно что превратить строгий контрольный список «обязательно» в более расслабленный «выбирай, что хочешь».

Когда это полезно: при работе с формами или данными, в которых могут быть заполнены не все поля.

interface Pizza {
  size: string;
  toppings: string[];
  delivery: boolean;
}

type PartialPizza = Partial<Pizza>;

const customPizza: PartialPizza = {
  size: "Large",
  toppings: ["Pepperoni", "Mushrooms"],
};

2. Required

Required обеспечивает наличие всех свойств типа T. Это все равно, что убедиться, что у вас есть все ключевые ингредиенты для вашего любимого блюда.

Когда это полезно: если вы хотите, чтобы определенные свойства всегда включались в ваши данные.

type RequiredPizza = Required<PartialPizza>;

const completePizza: RequiredPizza = {
  size: "Medium",
  toppings: ["Cheese", "Tomato"],
  delivery: true,
};

3. Readonly

Readonly создает тип, в котором все свойства типа T доступны только для чтения. Думайте об этом как о политике «бесконтактного управления» для свойств вашего объекта.

Когда это полезно: Когда вы хотите предотвратить случайное изменение ваших данных.

type ReadonlyPizza = Readonly<Pizza>;

const classicPizza: ReadonlyPizza = {
  size: "Small",
  toppings: ["Olives", "Onions"],
  delivery: false,
};

4. Pick

Pick помогает извлечь тип, содержащий только указанные свойства, из типа T. Думайте об этом как о создании собственной мини-версии объекта.

Когда это полезно: Когда вы хотите сузить свойства вашего объекта до самого необходимого.

type EssentialPizza = Pick<Pizza, 'size' | 'toppings'>;

const simplePizza: EssentialPizza = {
  size: "Medium",
  toppings: ["Tomatoes", "Cheese"],
};

5. Record

Record создает тип с указанными ключами типа Keys и значениями типа Value. Представьте себе, что вы создаете свой собственный словарь слов и их значений.

Когда это полезно: Когда вам нужно создать структурированное сопоставление между ключами и значениями определенного типа.

type FruitDictionary = Record<string, string>;

const fruits: FruitDictionary = {
  mango: "Yellow and delicious",
  apple: "Red and round",
};

6. Omit

Omit создает тип, исключая определенные свойства, перечисленные в разделе Keys, из типа T. Это похоже на редактирование ненужных частей изображения.

Когда это полезно: Когда вы хотите удалить определенные свойства из типа объекта.

type PizzaWithoutDelivery = Omit<Pizza, 'delivery'>;

const inPersonPizza: PizzaWithoutDelivery = {
  size: "Large",
  toppings: ["Bacon", "Jalapeno"],
};

7. Exclude

Exclude фильтрует определенные типы из объединения, которые можно назначить исключенному типу. Это все равно, что сказать: «Мне нужен только один вид закусок».

Когда это полезно: Когда вы хотите сузить возможные значения типа объединения.

type SnackOptions = "Cookies" | "Fruit";

// Excluding "Cookies" for a guest with dietary restrictions
type GuestSnackOptions = Exclude<SnackOptions, "Cookies">;

const guest1: GuestSnackOptions = "Fruit"; // Valid
const guest2: GuestSnackOptions = "Cookies";   // Error: 'Chips' is excluded

8. NonNullable

NonNullable гарантирует, что значение не является нулевым или неопределенным внутри объединения. Это ваш способ сказать: «Я хочу настоящего!»

Когда это полезно: когда вам нужно убедиться, что значение не отсутствует в типе объединения.

type NullableValue = string | null | undefined;
type SureValue = NonNullable<NullableValue>;
//same as type SureValue = string;

const certainValue: SureValue = "Absolutely!";

9. Extract

Extract сохраняет только те типы из объединения, которые можно назначить извлеченному типу. Это все равно что вылавливать свои любимые блюда из набора закусок.

Когда это полезно: Когда вы хотите извлечь определенные типы из типа объединения.

type SweetFruit = Extract<string | number | boolean, string>;
//same as type SweetFruit = string;

const favoriteFruit: SweetFruit = "Mango"; // Delicious choice!

10. Parameters

Parameters фиксируют типы параметров функции.

Когда это полезно: Когда нужно работать с типами параметров функции.

function cookDinner(mainCourse: string, sideDish: string): void {
  console.log(`Tonight's menu: ${mainCourse} with a side of ${sideDish}`);
}

type DinnerIngredients = Parameters<typeof cookDinner>;

const tonight: DinnerIngredients = ["Spaghetti", "Salad"];

11. ReturnType

ReturnType фиксирует тип возвращаемого значения функции. Это все равно, что знать, что ты получишь в качестве финального блюда.

Когда это полезно: Когда вы хотите знать, какой тип значения вернет функция.

function bakeCake(): string {
  return "A delicious cake!";
}

type CakeType = ReturnType<typeof bakeCake>;

const cake: CakeType = "Chocolate"; // Yum, cake time!

12. Awaited

Awaited извлекает разрешенный тип обещания, возвращаемого функцией. Это как получить настоящую еду после ожидания заказа.

Когда это полезно: Когда вы работаете с промисами и хотите знать, к чему они приведут.

async function fetchMeal(): Promise<string> {
  const response = await fetch("https://api.example.com/meal");
  return response.text();
}

type DeliveredMeal = Awaited<typeof fetchMeal>;

async function enjoyMeal(): Promise<void> {
  const meal: DeliveredMeal = await fetchMeal();
  console.log(`Enjoying a delicious meal: ${meal}`);
}

Бонус: Mutable

Mutable создает тип, в котором все свойства типа T являются изменяемыми. TypeScript не предлагает этот тип «из коробки», поэтому нам придется создать его самостоятельно.

Когда это полезно: когда у вас есть объект, доступный только для чтения, но вам нужно внести в него изменения.

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

type MutablePizza = Mutable<ReadonlyPizza>;

const dynamicPizza: MutablePizza = {
  size: "Extra Large",
  toppings: ["Jalapenos", "Tomatoes"],
  delivery: true,
};

Пример комбинации

Давайте рассмотрим несколько примеров, интегрируя различные типы утилит в TypeScript. Мы возьмем тему создания команды супергероев с разнообразными способностями. Используя типы утилит, мы смоделируем различные аспекты этого сценария.

// Step 1: Define the types of superhero abilities
type Ability = "Flight" | "Strength" | "Invisibility" | "Telekinesis";

// Step 2: Create utility types for different types of superheroes
type SuperheroBase = {
  name: string;
  abilities: Ability[];
};

type FlyingSuperhero = Required<Pick<SuperheroBase, "name">> & {
  abilities: ["Flight"];
};

type StrongSuperhero = Required<Pick<SuperheroBase, "name">> & {
  abilities: ["Strength"];
};

type InvisibleSuperhero = Required<Pick<SuperheroBase, "name">> & {
  abilities: ["Invisibility"];
};

type TelekineticSuperhero = Required<Pick<SuperheroBase, "name">> & {
  abilities: ["Telekinesis"];
};

// Step 3: Create some superhero instances using the utility types
const superman: FlyingSuperhero = {
  name: "Superman",
  abilities: ["Flight"],
};

const hulk: StrongSuperhero = {
  name: "Hulk",
  abilities: ["Strength"],
};

const invisibleWoman: InvisibleSuperhero = {
  name: "Invisible Woman",
  abilities: ["Invisibility"],
};

const jeanGrey: TelekineticSuperhero = {
  name: "Jean Grey",
  abilities: ["Telekinesis"],
};

// Step 4: Create a superhero team with various abilities
type SuperheroTeam = FlyingSuperhero | StrongSuperhero | InvisibleSuperhero | TelekineticSuperhero;

const mySuperheroTeam: SuperheroTeam[] = [superman, hulk, invisibleWoman, jeanGrey];

// Step 5: Define an async action that our superheroes can perform
async function performHeroicAction(hero: SuperheroTeam): Promise<string> {
  switch (hero.abilities[0]) {
    case "Flight":
      return "Rescued people from a tall building.";
    case "Strength":
      return "Lifted a fallen bridge to save civilians.";
    case "Invisibility":
      return "Sneaked past the enemy to gather information.";
    case "Telekinesis":
      return "Stopped a speeding car using telekinetic power.";
    default:
      return "Performed a mysterious heroic feat.";
  }
}

// Step 6: Let our superheroes perform actions and communicate asynchronously
async function superheroTeamAssemble(team: SuperheroTeam[]): Promise<void> {
  for (const hero of team) {
    const actionResult: Awaited<ReturnType<typeof performHeroicAction>> = await performHeroicAction(hero);
    const introduction = `${hero.name}: "${actionResult}"`;
    console.log(introduction);
  }
}

// Step 7: Assemble the superhero team and let them perform heroic actions
superheroTeamAssemble(mySuperheroTeam);
Важно отметить, что использование Awaited и ReturnType здесь сделано явно, чтобы показать вам, как их можно использовать вместе. TypeScript обычно достаточно умен, чтобы распознавать тип разрешенного значения обещания и самостоятельно применять этот вывод типа.

В этом примере показано, как можно использовать служебные типы TypeScript для моделирования более сложных сценариев, включающих асинхронную связь, асинхронные действия и динамический анализ типов. Это также добавляет дополнительный уровень веселья и игривости нашему примеру с командой супергероев!

Заключение

Служебные типы TypeScript — это встроенные манипуляторы типов, которые облегчают изменение и выполнение действий над установленными типами. Надеюсь, вы нашли эти примеры типов утилит TypeScript информативными. Это не конец; вы можете использовать эти служебные типы для создания собственных типов. Использование служебных типов может значительно улучшить ваш код, сделав его более пригодным для повторного использования, кратким и чистым.

Для получения дополнительной информации о том, как вы можете использовать Cosmic в своем приложении с готовой поддержкой Typescript, посетите нашу документацию или начните работу с Cosmic.

#JavaScript #React #TypeScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу