Пейджер

🌍 Привет мир! 👋

🌍 Привет мир! 👋

Скоро Новый год 🎄 и это заключительное чтиво в уходящем 2024, поговорим про TypeScript, а конкретно про infer.

🚀 Мотивация

Не сказать что тема очень популярная, но понимание работы infer keyword, позволит создавать более гибкие и адаптивные типы, кроме того появится способность к чтению типов которые предоставляются сторонними библиотеками.

⁉️ Что такое infer

Infer keyword в TypeScript используется в conditional types для создания типа из другого типа. Это может быть удобно для создания общих типов, которые работают со многими различными типами входных данных.

⚒️ База

Просто пример, который приоткроет замысел infer.

let num = 1;

type GetType<T> = T extends infer N ? N : never;

type ResultType = GetType<typeof num>; // number

Infer используется только в рамках conditional statement , и только в extends части. Если проговорить словами что здесь происходит, то выглядит это так:

Тип T (переданный как generic type, в примере это number) присваивается переменной N и поскольку условие T extends infer N всегда истинно, то условный тип всегда будет выводить N (number), что равносильно T (number) .

📝 Рабочий пример

Данный кейс я решал недавно у себя на рабочем проекте, поэтому ловите прям с “пылу с жару”.

Есть какой-то исторически образованный dictionary, он явно не идеальный, но что есть, то есть. Кстати выбран способ создания через as const и неспроста, Почему? Ну очевидно, читаем, я уже писал про это =)

const dictionary = {
  agent: {
    password: 'agentPassword',
    role: 'agentRole',
  },
  candidate: {
    password: 'candidatePassword',
    role: 'candidateRole',
  },
  contact: {
    role: 'contactRole',
  },
} as const;


✏️ Мы пишем новый функционал, и есть необходимость в создании функции, которая в качестве параметра принимает значение ключа role. И не хотелось бы, просто поставить тип string.

const logRole = (role: string) => {
    console.log(`role: ${role}`)
}


🫵 Кстати, а вы знаете что вернет такая функция logRole → (void)? Если нет, пишите в комментариях, сделаю подробный разбор на этот кейс в следующей статье о TypeScript.

Не переживаем, решение есть и оно (клевое === не костыльное).

type RoleTypeField<T> = T extends { role: infer U } ? U : never;


Что происходит в типе

📌 T extends { role: infer U }: Проверяется, является ли тип T объектом, который содержит поле role.

📌 infer U: Получаем тип значения, находящегося в поле role, и временно обозначаем его как U.

📌 ? U : never: Если условие выполняется (то есть если T имеет поле role), то типом RoleTypeField<T> будет тип U, представляющий значение поля role. Если условие не выполняется, результат будет never (или проще говоря объект будет скипнут) .

👇 Как пользоваться ?

type roleType = RoleTypeField<(typeof dictionary)[keyof typeof dictionary]>

const logRole = (role: roleType) => {
    console.log(`role: ${role}`)
}

logRole('agentRole') 
// ваш аргумент просто песня

logRole('большеЛайков')
// Argument of type '"большеЛайков"' is not assignable  
// to parameter of type 'roleType'.


📌 typeof dictionary: Получаем тип dictionary.

📌 keyof typeof dictionary: Извлекаем все ключи объекта dictionary в виде объединения строковых литералов. Получаем 'agent' | 'candidate' | 'contact' .

📌 (typeof dictionary)[keyof typeof dictionary]: Происходит выборка всех значений типа из объекта dictionary.

{
    readonly password: "agentPassword";
    readonly role: "agentRole";
} | {
    readonly password: "candidatePassword";
    readonly role: "candidateRole";
} | {
    readonly password: "contactPassword";
}


‼️ Как итог с помощью RoleTypeField получаем типы значений ключа role.

type roleType = "agentRole" | "candidateRole"


👇Важная информация👇

📌 Многие утилиты в TS уже имплементированы при помощи infer (ReturnType, Parameters и др.)

📌 В рамках одного extends можно делать несколько infer

type FS<T> = T extends [infer F, infer S, ...any[]] ? [F S] : never


💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#TYPESCRIPT
Медиа 1
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @ivanchikovitclub Открыть пост в Telegram