TLDR:
Это вторая глава серии, где я покажу вам, как избежать ошибок времени выполнения без письма тесты . Мы будем использовать только крепкие принципы Hydescript Chintcrient.
Вы можете скопировать исходный код вставки из примеров в свою IDE или Интернет TeampStry Playground И играй с этим самостоятельно.
Главы:
Вывод
Generics (текущий прочитанный)
В этой главе мы рассмотрим более продвинутый тип вывода и типа повторного использования с помощью Teamescript Regies.
В предыдущей главе о TeampScript вывод мы ввели
Тип выводатип&Как постоянный|
Поэтому, если вы не прочитали его, или вы не полностью понимаете эти концепции или синтаксис Tymdercript, проверьте главу 1.
Универсал
Дженерики имеют решающее значение для нашего нового информирования Tearpcript Mindset. Это позволяет нам выполнить реальную магию в одноклассниках. С Regrics мы сможем сделать вывод все, что мы хотим.
В этой главе мы представим
Дженерики + тип вывода
Тип проверки с помощью
расширяетсяподмножествоУсловия внутри универсальных
Тип вывод в условные типы
Обещание обертки
Типы полезных предприятий
Пользовательские дженерики Utils
Я не хочу дублировать Tymdercript Documentation, чтобы вы должны провести некоторое время, чтение Джезы Документация для лучшего понимания этой серии.
Вы можете вдохновить себя с полезными ресурсами, такими как:
- https://www.typescriptlang.org/docs/handbook/generics.html
- https://www.typescriptlang.org/docs/handbook/advanced-types.html
Итак, давайте посмотрим на краткий обзор функций Tymdescript, которые мы должны знать.
1. Дженерики + тип вывода
Одним из главных инструментов для создания многоразовых компонентов является универсал . Мы сможем создать компонент, который может работать над различными типами данных, а не один.
Мы можем комбинировать Джезы с помощью Tymdercript вывод. Вы можете легко создать Общий который будет использоваться в качестве аргумента нашей новой функции.
const unwrapKey =(arg: { key: T }) => arg.key;
Теперь мы просто позвоним эту функцию и получим тип на основе реализации.
const unwrapKey =(arg: { key: T }) => arg.key; // ts infer value1 as string const value1 = unwrapKey({ key: 'foo' }); // ts infer value1 as boolean const value2 = unwrapKey({ key: true }); // ts infer value1 as true const value3 = unwrapKey({ key: true } as const);
Tymdercript динамически инфицированы аргументы и возвращает значение функции, извлечение типа данных который передается как Общий ценность. Функция на 100% типа безопасной, даже если свойство ключ это тип агностики.
Документация: https://www.typescriptlang.org/docs/handbook/generics.html.
2. Тип проверки с использованием продлений подмножества
Ключевое слово Tearkcript увеличивается в качестве проверки подмножества для входящих типов данных. Мы просто определяем набор возможных вариантов для текущего универсального универсального.
const unwrapKey =(arg: { key: T }) => arg.key; const ok = unwrapKey({ key: true }); const willNotWork = unwrapKey({ value: 'value should be boolean or number' });
Документация: https://www.typescriptlang.org/docs/handbook/generics.html#generic-constraints
3. Условия внутри универсальных
Есть еще одно использование расширяться Ключевое слово для проверки, если тип соответствует шаблону. Если это так, TeampScript применяет тип за вопросительным знаком ? . Если нет, он использует тип за столбце : . Он ведет себя так же, как Темнарный оператор в JavaScript.
type Foo= T extends number ? [number, string] : boolean const a: Foo = [2, '3'] const b: Foo = true
Если тип T это Номер Полученный тип – кортеж, если нет, это просто логическое.
Документация: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
Эта функция может быть красиво используется с типографическими типами типа. https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types
4. Тип вывод в условных типах
Типографы Ключевое слово вывод является более продвинутой особенностью. Он может выводить тип внутренней части декларации условия общего типа, как в примере ниже.
type ReturnFnType= T extends (...args: any[]) => infer R ? R : any; const getUser = (name: string) => ({ id: `${Math.random()}`, name, friends: [], }) type GetUserFn = typeof getUser type User = ReturnType
Подробнее вы будете читать больше о RetentType Generic в этой главе.
Я рекомендую прочитать документацию по типу вывода в типов условиях (и использование ключевого слова ofitferfer) https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types
5. Обещание обертки
TeampScript также отлично работает с Обещания
Есть встроенный Обещание <...> Общий, который мы будем использовать в асинхронных операциях. Обещание Generic – это просто обертка, которая вступает в ваши данные в обещании «класс».
TypeyctScript имеет идеальную поддержку для обещания для async , ждать Синтаксис сахара, такой как:
const getData = () => {
return Promise.resolve(3)
}
// each async function wrap result into Promise()
const main = async () => {
// await unwrap Promise wrapper
const result = await getData()
}
6. Типы полезных предприятий
Tymdercript предоставляет типы утилиты для упрощения преобразований общего типа. Эти коммунальные услуги по умолчанию доступны в глобальном масштабе в вашем проекте.
Документация: https://www.typescriptlang.org/docs/handbook/utivy-types.html.
Мы сосредоточимся на двух из них Returntype <...> и Частичный <...> Отказ
6.1 returntype <…>
Returntype – это абсолютно феноменальные Функция TearmScript, которую мы увидим во многих других примерах!
Определение этого универсала выглядит так:
type ReturnTypeany> = T extends (...args: any) => infer R ? R : any;
Как видите, ReturnType просто занимает некоторую функцию и получает тип возвращаемого значения. Это позволяет нам выполнять более жесткий тип вывода. Давайте посмотрим это в этом примере
const getUser = (name: string) => ({
id: Math.random(),
name,
isLucky: Math.random() % 2 === 0
})
type User = ReturnType
Это отличная функция для нашей новой типографии Manning Programming Mental Manager, которую мы представили в предыдущей главе.
Еще один прохладный пример Returntype <...> Получает некоторое конкретное значение для чтения только от объекта внутри функции.
const foo = () => ({ foo: 'bar' } as const);
type FooReturnValue= ReturnType
type bar = FooReturnValue['foo']
6.2 Частичный <…>
В этом примере мы будем использовать В Keyof Функция синтаксиса. Если вы хотите узнать больше об этом, прочитайте расширенную документацию Tymdercript. https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types Отказ
Общий Частичный Определение выглядит как:
/** * Make all properties in T optional */ type Partial= { [P in keyof T]?: T[P]; };
Как видите, он просто заворачивает объект JavaScript и установить его ключи, возможно, не определены. Значок вопросительного вопроса после того, как название ключа делает ключ необязательно. Вы можете использовать этот универсальный, если вы хотите использовать просто отдельно объект.
const user = {
id: Math.random(),
name: 'Foo',
isLucky: Math.random() % 2 === 0
}
type PartialUser = Partial
7. Пользовательские дженерики Utils
В этом разделе мы собираемся создать дженерики помощника.
7.1 ждать
Ждать это утилита, которая берет Обещание <...> Обернутое значение и удалить Обещание обертка и оставляет только извлеченные данные.
Попробуйте представить, что у вас уже есть async Функция JavaScript. Как мы знаем, каждый async Функция оборачает результат в Обещание Общая обертка. Так что если мы позвоним Returntype Для асинхронизации мы получаем некоторое значение, завернутое в Обещание общий.
Мы можем извлечь возвратную стоимость из обещания, используя Returntype и Ждать :
export type Await= T extends Promise ? R : T // helper function to emit server delay const delay = (time: number) => { return new Promise(res => { setTimeout(() => { res() }, time) }) } const getMockUserFromServer = async () => { // some asynchronous business logic await delay(2000) return { data: { user: { id: "12", } } } } type Response = Await >
Он добавляет еще одну возможность вывода более продвинутых типов скрытых данных в код JavaScript.
7.2 РекурсийныйAtivePartial.
Это просто улучшено Частичный <...> Generic, который мы вводим несколько пунктов назад. Декларация выглядит так:
// inspiration: https://stackoverflow.com/a/51365037 type RecursivePartial= { [P in keyof T]?: // check that nested value is an array // if yes, apply RecursivePartial to each item of it T[P] extends (infer U)[] ? RecursivePartial[] : T[P] extends object ? RecursivePartial : T[P]; };
RecursivePartial изначально вдохновлен этим вопросом переполнения стека https://stackoverflow.com/a/51365037
Как вы видите, он просто рекурсивно устанавливает все ключевые ключи в вложенном объекте, чтобы быть, возможно, undefined Отказ
Объедините все двоеги в один чудовищный шедевр
Хорошо, мы многому научились о SpaceStry Generics. Теперь мы будем объединить наши знания вместе в следующих параграфах.
Представьте, что у нас есть приложение, которое делает звонки в Backend Service. Backenc Возвращает данные о в настоящее время зарегистрированном пользователю. Для лучшего развития мы используем издеватые ответы с сервера. Наша цель состоит в том, чтобы извлечь тип данных ответа из издеватых вызовов API (например, Getmemock Функция в примере).
Мы не верим в правильность ответа с сервера, поэтому мы делаем все поля необязательными.
Давайте определим нашими универсальными универсальными универсальными универсальными и просто примените однострочную последовательность типографии для вывода типа Пользователь из макета функции.
// ------------------- utils.ts ---------------------- // inspiration https://stackoverflow.com/a/57364353 type Await= T extends { then(onfulfilled?: (value: infer U) => unknown): unknown; } ? U : T; // inspiration: https://stackoverflow.com/a/51365037 type RecursivePartial = { [P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial[] : T[P] extends object ? RecursivePartial : T[P]; }; // helper function to emit server delay const delay = (time: number) => new Promise((res) => { setTimeout(() => { res(); }, time); }); // ----------------- configuration.ts --------------- const USE_MOCKS = true as const; // ----------------- userService.ts ----------------- const getMeMock = async () => { // some asynchronous business logic await delay(2000); return { data: { user: { id: '12', attrs: { name: 'user name' } } } }; }; const getMe = async () => { // TODO: call to server return getMeMock(); }; type GetMeResponse = Await > type User = RecursivePartial
Ты тоже видишь? Мы взяли почти чистый код JavaScript и используя наш Typearcript Utils, Мы добавили только 2 строки Tymdercript Code и выведите все статические типы данных из этой реализации JavaScript! Мы все еще можем написать код JavaScript и улучшив его с помощью Teamescript Micro Antotions. Все это с минимальным количеством усилий без скучного интерфейса.
И, в верхней части, каждый раз, когда вы хотите получить доступ к некоторому подслушиванию типа пользователя, ваш IDE автоматически добавит Дополнительный оператор цепи (Имя * ? *). Поскольку мы сделали все поля необязательными, доступ к вложенным значениям не может бросить новую ошибку.
Если дополнительное цепочка не работает, вы должны настроить "Strictnullchecks": правда в вашем tsconfig.json.
И это все! В этот момент вы можете сделать вывод, что вы хотите, от вашей реализации JavaScript, и вы сможете использовать безопасный интерфейс типа без дополнительных статических типов.
Обращать внимание! Не нарушайте дженерики!
Я считаю, что в вашем среднем кодексе нет больших сложных функций с трудом для понимания моделей данных. Так что, пожалуйста, не перевыпивайте свой Джезы Отказ Каждый раз, когда вы создаете новый Общий Подумайте, если необходимо создать такую избыточную абстрактную абстракцию, которая уменьшает читаемость кода/типа. Так что если вы напишите тип вручную, будь строгий и чистый . Дженерики потрясающие особенно для некоторых общего назначения Типы утилит ( returntype , Ждать
* Плохая практика * 😒
type UserTemplate= { id: string, name: string } & T type User1 = UserTemplate<{ age: number }> type User2 = UserTemplate<{ motherName: string }> type User = User1 | User2
* Хорошая практика * 🎉
type UserTemplate = { id: string, name: string }
type User1 = UserTemplate & { age: number }
type User2 = UserTemplate & { motherName: string }
type User = User1 | User2
Альтернативное обозначение для хорошей практики 🎉
type User = {
id: string,
name: string
} & (
{ age: number }
| { motherName: string }
)
Вывод
В главе один Мы узнали основы Tymdercript и его функции. У нас есть новые идеи об использовании статического типа вывода для JavaScript.
В этой главе мы узнали, как использовать дженерики, и когда их уместно использовать их.
Вы хотите больше?
Если вы заинтересованы в более продвинутом использовании типа, посмотрите на мои другие статьи.
Объект.Fromentries
REPYPE Объект.Fromentries Чтобы поддержать все виды кортежей https://dev.to/svehla/typescript-object-fromentries-389c
Deepmerges
Как реализовать Deepmerge Для статических типов https://dev.to/svehla/typescript-how-to-deep-merge-170c
Если вам понравилось прочитать статью, не забудьте понравиться, чтобы сказать мне, что имеет смысл продолжать.
Оригинал: “https://dev.to/svehla/typescript-generics-stop-writing-tests-avoid-runtime-errors-pt2-2k62”