Typescript. Утилиты. Часть 3 (Parameters, ReturnType)
Первая часть (Readonly, Required, Partial): https://t.me/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://t.me/react_junior/429
Утилиты
Возьмем функцию:
В утилиту нужно передать тип этой функции, а не ее значение:
Утилита
Утилита
#typescript
Первая часть (Readonly, Required, Partial): https://t.me/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://t.me/react_junior/429
Утилиты
Parameters
и ReturnType
работают с функциями и могут, соответственно, получать типы входных параметров или возвращаемого значения.Возьмем функцию:
function add(num1: number, num2: number): number {
return num1 + num2;
}
В утилиту нужно передать тип этой функции, а не ее значение:
typeof add
Утилита
Parameters
вернет кортеж их типов входных аргументов: [num1: number, num2: number]
Утилита
ReturnType
вернет тип возвращаемого значения:number
#typescript
👍3
TypeScript. Условные типы
Статья (англ): https://javascript.plainenglish.io/use-typescript-conditional-types-like-a-pro-7baea0ad05c5
Утилиты Exclude, Extract, NonNullable, Parameters, and ReturnType используют "условные типы" (Conditional Types).
В статье подробно разбирается их внутреннее устройство, разобравшись с которым можно создавать свои похожие утилиты.
Общий синтаксис условных типов выглядит так:
Берется некий тип
Простейшая утилита
Она просто определяет, является ли переданный тип строкой.
Но можно делать и намного более сложные вещи.
Распределенные условные типы
Если передать в утилиту объединение типов, на выходе тоже можно получить объединение, потому что операция выполняется для каждого члена объединения - это называется _распределенные условные типы__ (distributed conditional type).
Но это работает только для "голых" типов, не обернутых в массивы/кортежи/промисы.
#typescript #ссылки #подкапотом
Статья (англ): https://javascript.plainenglish.io/use-typescript-conditional-types-like-a-pro-7baea0ad05c5
Утилиты Exclude, Extract, NonNullable, Parameters, and ReturnType используют "условные типы" (Conditional Types).
В статье подробно разбирается их внутреннее устройство, разобравшись с которым можно создавать свои похожие утилиты.
Общий синтаксис условных типов выглядит так:
T extends U ? X : Y
Берется некий тип
T
и присваивается типу U
(проверяется, входит ли T
в U
). Если да, возвращается X
, если нет - Y
(X
и Y
могут быть чем угодно, например, тем же исходным типом T
).Простейшая утилита
IsString
такого рода может выглядеть так:T extends string ? true : false
Она просто определяет, является ли переданный тип строкой.
Но можно делать и намного более сложные вещи.
Распределенные условные типы
Если передать в утилиту объединение типов, на выходе тоже можно получить объединение, потому что операция выполняется для каждого члена объединения - это называется _распределенные условные типы__ (distributed conditional type).
Но это работает только для "голых" типов, не обернутых в массивы/кортежи/промисы.
#typescript #ссылки #подкапотом
👍4
TypeScript. Пересечения
Статья (англ.): https://javascript.plainenglish.io/using-typescript-intersection-types-like-a-pro-a55da6a6a5f7
Статья подробно рассказывает об операторе
Если он работает с примитивными значениями, то понять, каким будет результат просто - этот оператор работает как логическое И:
Если один из операндов
Если один из операндов
Если же операнды являются объектами, то оператор работает с каждым полем этих объектов.
Если есть одинаковые поля с конфликтующими типами, будет
В статье есть интересный пример использования пересечения для функций с разной сигнатурой - фактически перегрузка функций с разными наборами параметров.
А в заключение дается пример использования пересечения вместе с MappedTypes, над которым можно немного поломать голову.
#typescript #ссылки #подкапотом
Статья (англ.): https://javascript.plainenglish.io/using-typescript-intersection-types-like-a-pro-a55da6a6a5f7
Статья подробно рассказывает об операторе
&
в TypeScript.Если он работает с примитивными значениями, то понять, каким будет результат просто - этот оператор работает как логическое И:
type T1 = 1 & number; // 1
type T2 = '1' & string; // '1'
type T3 = number & string; // never
Если один из операндов
never
, то результатом будет never
.Если один из операндов
any
, то результатом будет any
.type T4 = any & 1; // any
type T5 = any & boolean; // any
type T6 = any & never; // never
Если же операнды являются объектами, то оператор работает с каждым полем этих объектов.
interface Point {
x: number;
y: number;
}
interface Named {
name: string;
}
type NamedPoint = Point & Named;
// { x: number, y: number, name: string }
Если есть одинаковые поля с конфликтующими типами, будет
never
:interface A {
n: number
}
interface B {
n: string
}
type C = A & B; // { n: never }
В статье есть интересный пример использования пересечения для функций с разной сигнатурой - фактически перегрузка функций с разными наборами параметров.
А в заключение дается пример использования пересечения вместе с MappedTypes, над которым можно немного поломать голову.
#typescript #ссылки #подкапотом
👍3
Использование Typescript с React – руководство для новичков
Статья (рус.): https://habr.com/ru/company/otus/blog/456124/
Небольшое руководство для тех, кто только пытается совместить React и TypeScript в одном приложении. Рассказывает, где именно использовать типы в React.
1) Вместо PropTypes для пропсов компонента.
Тут же мы видим полезный тип
Если кроме указнных пропсов нужно принимать еще стандартные атрибуты HTML-элементов (`style`,
2) Для аргументов в обработчиках событий.
Еще полезный тип
3) Использование дженериков с компонентами
Компоненты React могут принимать обобщенные типы, которые затем могут использоваться для типизации, например, пропсов.
4) Хуки
Типизации требуют в основном два React-хука:
В статье есть пример типизации редуктора, он немного навороченный, но в целом понятный. Главное разобраться, как типизируются экшены с их полезной нагрузкой. Для этого создается отдельный сложный тип
5) typeof и keyof для типизирования компонентов с разными вариантами
Очень удобно, например, для кнопок, которые могут иметь разные стили. При этом набор возможных типов берется из ключей объекта.
#typescript
Статья (рус.): https://habr.com/ru/company/otus/blog/456124/
Небольшое руководство для тех, кто только пытается совместить React и TypeScript в одном приложении. Рассказывает, где именно использовать типы в React.
1) Вместо PropTypes для пропсов компонента.
export interface StandardComponentProps {
title?: string
children: React.ReactNode
}
export function StandardComponent({
children,
title = 'Default Title',
}: StandardComponentProps) {
}
Тут же мы видим полезный тип
ReactNode
.Если кроме указнных пропсов нужно принимать еще стандартные атрибуты HTML-элементов (`style`,
aria-hidden
, `className`), нужно просто расширить существующий встроенный интерфейс React.HTMLAttributes.2) Для аргументов в обработчиках событий.
function onFocus(e: React.FocusEvent) {
console.log('Focused!', e.currentTarget)
}
Еще полезный тип
FocusEvent
. Помимо него есть еще MouseEvent
и, вероятно, ряд других событий.3) Использование дженериков с компонентами
Компоненты React могут принимать обобщенные типы, которые затем могут использоваться для типизации, например, пропсов.
4) Хуки
Типизации требуют в основном два React-хука:
useRef
и useReducer
, остальные работают из коробки. Для этого тоже используются дженерики.В статье есть пример типизации редуктора, он немного навороченный, но в целом понятный. Главное разобраться, как типизируются экшены с их полезной нагрузкой. Для этого создается отдельный сложный тип
Action
, который использует условные типы и пересечения.5) typeof и keyof для типизирования компонентов с разными вариантами
Очень удобно, например, для кнопок, которые могут иметь разные стили. При этом набор возможных типов берется из ключей объекта.
const styles = {
primary: {
color: 'blue',
},
danger: {
color: 'red',
},
};
type StylesType = typeof styles;
export type ButtonType = keyof StylesType;
interface ButtonProps {
type: ButtonType
};
export function Button({ type = 'primary' }: ButtonProps) {
}
#typescript
Хабр
Использование Typescript с React – руководство для новичков
Друзья, в преддверии выходных хотим поделиться с вами еще одной интересной публикацией, которую хотим приурочить к запуску новой группы по курсу «Разработчик Jav...
👍3👎1
Typescript. Утилиты. Часть 4 (Uppercase, Lowercase, Capitalize, Uncapitalize)
Первая часть (Readonly, Required, Partial): https://t.me/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://t.me/react_junior/429
Третья часть (Parameters, ReturnType): https://t.me/react_junior/430
В этот раз 4 очень простые утилиты, которые имеют дело с регистром символов:
- Uppercase
- Lowercase
- Capitalize
- Uncapitalize
#typescript
Первая часть (Readonly, Required, Partial): https://t.me/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://t.me/react_junior/429
Третья часть (Parameters, ReturnType): https://t.me/react_junior/430
В этот раз 4 очень простые утилиты, которые имеют дело с регистром символов:
- Uppercase
- Lowercase
- Capitalize
- Uncapitalize
#typescript
🔥2
TypeScript. Ключевое слово infer
Весь вечер пытаюсь разобраться с ключевым словом infer в TypeScript 🙂 Не сказать, что концепция самая очевидная, но вроде и не чрезмерно сложная, если я, конечно, все правильно понимаю.
Итак, infer может "выводить" один тип на основании другого. Использовать это ключевое слово можно только в условных конструкциях вместе с extend. Выведенный тип затем можно использовать, например, вернуть из условной конструкции.
Подробнее об условных типах: https://t.me/react_junior/431
Самый понятный для меня (но вероятно не самый популярный) пример использования infer - на приложенном скрине (взято со StackOverflow).
Утилита UnpackArrayType получает обобщенный тип T.
Затем ставится условие:
T extends (infer R)[]
Эта конструкция буквально означает, "можно ли представить T в виде массива элементов какого-нибудь типа R". При этом тип R буквально "выводится" из типа T с помощью infer. Если T равно number[], то R будет равно number.
Если условие получилось выполнить, возвращается свежевыведенный тип R.
Неплохой разбор infer есть в статье Understanding infer in TypeScript (англ.)
Там автор начинает с более простых концепций: типа never, оператора extends, объединений, а затем переходит к работе с функциями и собственно ключевому слову infer.
К слову, именно infer лежит в основе работы утилиты ReturnType.
В конце статьи приводяется некоторые популярные кейсы использования infer, например, выведение возвращаемого типа из промиса.
#ссылки #typescript #подкапотом #infer
Весь вечер пытаюсь разобраться с ключевым словом infer в TypeScript 🙂 Не сказать, что концепция самая очевидная, но вроде и не чрезмерно сложная, если я, конечно, все правильно понимаю.
Итак, infer может "выводить" один тип на основании другого. Использовать это ключевое слово можно только в условных конструкциях вместе с extend. Выведенный тип затем можно использовать, например, вернуть из условной конструкции.
Подробнее об условных типах: https://t.me/react_junior/431
Самый понятный для меня (но вероятно не самый популярный) пример использования infer - на приложенном скрине (взято со StackOverflow).
Утилита UnpackArrayType получает обобщенный тип T.
Затем ставится условие:
T extends (infer R)[]
Эта конструкция буквально означает, "можно ли представить T в виде массива элементов какого-нибудь типа R". При этом тип R буквально "выводится" из типа T с помощью infer. Если T равно number[], то R будет равно number.
Если условие получилось выполнить, возвращается свежевыведенный тип R.
Неплохой разбор infer есть в статье Understanding infer in TypeScript (англ.)
Там автор начинает с более простых концепций: типа never, оператора extends, объединений, а затем переходит к работе с функциями и собственно ключевому слову infer.
К слову, именно infer лежит в основе работы утилиты ReturnType.
В конце статьи приводяется некоторые популярные кейсы использования infer, например, выведение возвращаемого типа из промиса.
#ссылки #typescript #подкапотом #infer
👍5
Статья (англ.): https://levelup.gitconnected.com/using-typescript-infer-like-a-pro-f30ab8ab41c7
Еще немного про infer (начало здесь)
В статье приводится очень хорошее пошаговое объяснение того, как работает это ключевое слово.
Infer буквально распаковывает тип и позволяет вывести из него другой тип.
Рассматривается тот же пример с распаковкой массива и получением типа элемента (только подробнее и с анимацией).
Кроме того есть примеры с распаковкой аргументов и возвращаемого значения функций (так работает под капотом утилита ReturnType) и распаковкой ключей объекта.
Важно помнить, что infer может использоваться только в условных типах (`extends`) и после "захвата" доступен только в true-части выражения.
Во второй части статьи рассматриваются тонкости работы ключевого слова infer, например, при множественных типах (иногда в результате получается объединение типов, а иногда пересечение), а также сочетание нескольких условий.
В конце задачка, которая сломала мой мозг 🤯
#typescript #infer
Еще немного про infer (начало здесь)
В статье приводится очень хорошее пошаговое объяснение того, как работает это ключевое слово.
Infer буквально распаковывает тип и позволяет вывести из него другой тип.
Рассматривается тот же пример с распаковкой массива и получением типа элемента (только подробнее и с анимацией).
Кроме того есть примеры с распаковкой аргументов и возвращаемого значения функций (так работает под капотом утилита ReturnType) и распаковкой ключей объекта.
Важно помнить, что infer может использоваться только в условных типах (`extends`) и после "захвата" доступен только в true-части выражения.
Во второй части статьи рассматриваются тонкости работы ключевого слова infer, например, при множественных типах (иногда в результате получается объединение типов, а иногда пересечение), а также сочетание нескольких условий.
В конце задачка, которая сломала мой мозг 🤯
#typescript #infer
👍4
По TypeScript получилось довольно много материала (и еще будет 😄), поэтому добавлены новые теги для сложных тем: #infer, #дженерики и #tsдекораторы
Все теги тут: https://t.me/react_junior/84
Все теги тут: https://t.me/react_junior/84
Telegram
React Junior
Список тегов для более удобного поиска постов
👉 Основные понятия
#компоненты
#jsx
#жизненныйциклкомпонента
#виртуальныйdom
#состояние
#обработкасобытий
#потокданных
#ключи
#формы
#рефы
#hoc
#рендерпропсы
#контекст
#порталы
#хуки
👉 Управление состоянием…
👉 Основные понятия
#компоненты
#jsx
#жизненныйциклкомпонента
#виртуальныйdom
#состояние
#обработкасобытий
#потокданных
#ключи
#формы
#рефы
#hoc
#рендерпропсы
#контекст
#порталы
#хуки
👉 Управление состоянием…
🔥3
TypeScript. Шаблонные литералы
Статья (англ.): https://javascript.plainenglish.io/how-to-use-typescript-template-literal-types-like-a-pro-2e02a7db0bac
В типах тоже можно использовать шаблонные строки, а вставлять в них можно другие типы (в том числе, объединения типов).
В статье подробно и с картинками рассказано, во что именно компилируются типы с использованием шаблонных строк.
В шаблонных строках можно также использовать утилиты, работающие со строками (Uppercase, Lowercase, Capitalize, Uncapitalize).
Также их можно использовать в условных типах в сочетании с ключевым словом infer для создания очень мощных условий.
В статье разобрано использование шаблонных строк для Key Remapping (переименования ключей в сопоставимых типах).
А в самом конце есть прекрасный пример рекурсивной работы с типами.
#typescript
Статья (англ.): https://javascript.plainenglish.io/how-to-use-typescript-template-literal-types-like-a-pro-2e02a7db0bac
В типах тоже можно использовать шаблонные строки, а вставлять в них можно другие типы (в том числе, объединения типов).
type Alignment = 'start' | 'end';
type Side = 'top' | 'right' | 'bottom' | 'left';
type AlignedPlacement = `${Side}-${Alignment}`;
В статье подробно и с картинками рассказано, во что именно компилируются типы с использованием шаблонных строк.
В шаблонных строках можно также использовать утилиты, работающие со строками (Uppercase, Lowercase, Capitalize, Uncapitalize).
Также их можно использовать в условных типах в сочетании с ключевым словом infer для создания очень мощных условий.
В статье разобрано использование шаблонных строк для Key Remapping (переименования ключей в сопоставимых типах).
А в самом конце есть прекрасный пример рекурсивной работы с типами.
#typescript
🔥3👍2
Typescript. Утилиты. Часть 5 (Pick, Omit)
Первая часть (Readonly, Required, Partial): https://t.me/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://t.me/react_junior/429
Третья часть (Parameters, ReturnType): https://t.me/react_junior/430
Четвертая часть (Uppercase, Lowercase, Capitalize, Uncapitalize): https://t.me/react_junior/435
Утилита
Эта утилита похожа на Mapped Types, только Mapped Types берут полный набор ключей из исходного типа, а для
#typescript
Первая часть (Readonly, Required, Partial): https://t.me/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://t.me/react_junior/429
Третья часть (Parameters, ReturnType): https://t.me/react_junior/430
Четвертая часть (Uppercase, Lowercase, Capitalize, Uncapitalize): https://t.me/react_junior/435
Утилита
Pick
получает два параметра: исходный тип и набор ключей. Результат работы - новый тип на основе исходного, в который входят только указанные ключи.Эта утилита похожа на Mapped Types, только Mapped Types берут полный набор ключей из исходного типа, а для
Pick
набор ключей заранее указан.Omit
, соответственно, работает наоборот, берет все ключи, кроме указанных. Под капотом использует Pick
и Exclude
, чтобы получить набор нужных для типа ключей.#typescript
Telegram
React Junior
TypeScript. Утилиты (Readonly, Required, Partial)
TypeScript не просто дает возможность указыать типы для переменных и параметров и тем самым отслеживать ошибки. Он еще предлагает большой инструментарий для манипуляций с типами, превращения одних типов в…
TypeScript не просто дает возможность указыать типы для переменных и параметров и тем самым отслеживать ошибки. Он еще предлагает большой инструментарий для манипуляций с типами, превращения одних типов в…
👍1🔥1
TypeScript. 15 самых популярных утилит
Статья (англ.): https://javascript.plainenglish.io/15-utility-types-that-every-typescript-developer-should-know-6cf121d4047c
С большинством из перечисленных в статье утилит мы уже знакомы.
Partial, Required, Readonly
Функциональность этих утилит разбирали здесь: https://t.me/react_junior/413
А подкапотную реализацию здесь (статья о Mapped Types): https://t.me/react_junior/428
Для перебора ключей используется конструкция
Exclude, Extract, NonNullable
Функциональность тут: https://t.me/react_junior/429
Реализованы на условных типах: https://t.me/react_junior/431
Члены одного набора типов сопоставляются с членами второго набора с помощью конструкции
Pick, Omit
Функциональность и реализация тут: https://t.me/react_junior/442
Напоминают Mapped Types.
Parameters, ReturnType
Функциональность тут: https://t.me/react_junior/430
В реализации используется ключевое слово infer https://t.me/react_junior/439, чтобы вытащить нужные типы из полученного типа функции.
Uppercase, Lowercase, Capitalize, Uncapitalize
Функциональность здесь: https://t.me/react_junior/435
Record
С этой утилитой мы еще не встречались.
Она принимает два обобщенных типа: набор ключей Keys и тип значений Type. Из них формируется новый тип, в котором есть все ключи из Keys и каждому из них соответствует значение типа Type.
Условно это выглядит так:
#typescript
Статья (англ.): https://javascript.plainenglish.io/15-utility-types-that-every-typescript-developer-should-know-6cf121d4047c
С большинством из перечисленных в статье утилит мы уже знакомы.
Partial, Required, Readonly
Функциональность этих утилит разбирали здесь: https://t.me/react_junior/413
А подкапотную реализацию здесь (статья о Mapped Types): https://t.me/react_junior/428
Для перебора ключей используется конструкция
P in keyof T
.Exclude, Extract, NonNullable
Функциональность тут: https://t.me/react_junior/429
Реализованы на условных типах: https://t.me/react_junior/431
Члены одного набора типов сопоставляются с членами второго набора с помощью конструкции
T extends U ? X : Y
Pick, Omit
Функциональность и реализация тут: https://t.me/react_junior/442
Напоминают Mapped Types.
Parameters, ReturnType
Функциональность тут: https://t.me/react_junior/430
В реализации используется ключевое слово infer https://t.me/react_junior/439, чтобы вытащить нужные типы из полученного типа функции.
Uppercase, Lowercase, Capitalize, Uncapitalize
Функциональность здесь: https://t.me/react_junior/435
Record
С этой утилитой мы еще не встречались.
Она принимает два обобщенных типа: набор ключей Keys и тип значений Type. Из них формируется новый тип, в котором есть все ключи из Keys и каждому из них соответствует значение типа Type.
Условно это выглядит так:
type Keys = 101 | 102 | 103; // набор ключей
type User = { name: string; age: number }; // тип значений
// результат
type Record = {
101: User,
102: User,
103: User
}
#typescript
Medium
TypeScript Visualized: 15 Most Used Utility Types
15 Utility Types that Every TypeScript Developer Should Know
👍3🔥2
10 вещей, которые нужно знать о классах в TypeScript
Статья (англ.): https://levelup.gitconnected.com/10-things-you-need-to-know-about-typescript-classes-f58c57869266
Достаточно полный справочник по классам в TypeScript.
Первые пункты простые:
1. Статические поля и поля класса
2. Геттеры и сеттеры
3. Наследование классов (и реализация интерфейсов)
4. Абстрактные классы
5. Модификаторы доступа (и их сочетание с ECMAScript Private Fields)
6. Class Expressions
7. Использование дженериков в классах (https://t.me/react_junior/405)
Дальше посложнее: про конструкторы (и абстрактные конструкторы) и про использование в качестве типа самого класса и
Но если что тип для функции-конструктора на скрине.
#typescript
Статья (англ.): https://levelup.gitconnected.com/10-things-you-need-to-know-about-typescript-classes-f58c57869266
Достаточно полный справочник по классам в TypeScript.
Первые пункты простые:
1. Статические поля и поля класса
2. Геттеры и сеттеры
3. Наследование классов (и реализация интерфейсов)
4. Абстрактные классы
5. Модификаторы доступа (и их сочетание с ECMAScript Private Fields)
6. Class Expressions
7. Использование дженериков в классах (https://t.me/react_junior/405)
Дальше посложнее: про конструкторы (и абстрактные конструкторы) и про использование в качестве типа самого класса и
typeof Class
. Это все пока не очень понятно, как использовать.Но если что тип для функции-конструктора на скрине.
#typescript
👍3🔥2
Next.js + TypeScript
Для описания страниц в Next-приложении нам потребуется тип
#nextjs #серверныйрендеринг #typescript
Для описания страниц в Next-приложении нам потребуется тип
NextPage
(импортируется из пакета next). Это дженерик, который принимает тип пропсов компонента.#nextjs #серверныйрендеринг #typescript
👍2🔥1
Не могу удержаться и не поделиться) Вчера впервые потребовалось использовать
Ни на что не претендую, просто небольшой пример практического применения не самой простой концепции.
#примерыкода #typescript #infer
infer
в боевых условиях: https://telegra.ph/Infer-v-TypeScript-primer-ispolzovaniya-01-21Ни на что не претендую, просто небольшой пример практического применения не самой простой концепции.
#примерыкода #typescript #infer
Telegraph
Infer в TypeScript: пример использования
Мой первый самостоятельный кейс использования ключевого слова infer. Не могу не поделиться :) Есть условная функция fetchAndFormat, которая получает данные из api и форматирует их. У нее два аргумента: fetcherFn и formatterFn. Причем второй - необязательный…
👍8
TypeScript в Next.js
Соберем в одном месте типы, которые использует Next:
Данные для серверного рендеринга - GetStaticProps, GetStaticPaths, GetServerSideProps
API-роуты - NextApiRequest, NextApiResponse
Тип
Компонент App - AppProps
#nextjs #документация #typescript
Соберем в одном месте типы, которые использует Next:
Данные для серверного рендеринга - GetStaticProps, GetStaticPaths, GetServerSideProps
import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next';
export const getStaticProps: GetStaticProps = async function (context) {
// ...
}
export const getStaticPaths: GetStaticPaths = async function () {
// ...
}
export const getServerSideProps: GetServerSideProps = async function (context) {
// ...
}
API-роуты - NextApiRequest, NextApiResponse
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ name: 'John Doe' })
}
Тип
NextApiResponse
может также принимать обобщенный тип данных ответа.Компонент App - AppProps
import type { AppProps } from 'next/app'
export default function MyApp({ Component, pageProps }: AppProps) {
// ...
}
#nextjs #документация #typescript
👍3🔥1
React: самые используемые типы
Статья (англ.): https://jser.dev/2023-05-31-react-types-in-typescript/
Автор статьи сделал подборку типов, используемых в React, чтобы нам не пришлось.
1. ReactElement
Главный "строительный" метод React - React.createElement(). Он принимает конфиг элемента, который нужно создать - его и описывает интерфейс ReactElement.
ReactElement или JSX.Element (то же самое, просто алиас) - это то, что должно быть возвращено из JSXElementConstructor (из функционального или классового компонента).
2. ReactNode
Это "надтип" для ReactElement, как и в DOM - есть ноды (включают комментарии и текстовые узлы), а есть их подмножество - элементы.
В тип ReactNode входят ReactElement, строки, числа, булевы значения, фрагменты, порталы и даже null и undefined
3. FunctionComponent
Интерфейс, описывающий функциональный компонент
4. RefObject и MutableRefObject
Типы, описывающие рефы, созданные хуком
У
5. ComponentProps
Обобщенный тип, позволяющий "извлечь" из типа компонента его пропсы. Под капотом использует infer.
6. Dispatch и SetStateAction
Эти типы описывают самый популярный хук
Тип
7. События
С типизацией событий в React всегда сложно. Есть два подхода:
- типизировать само событие (SyntheticEvent), которое приходит в обработчик в виде аргумента, например, MouseEvent
- или типизировать сам обработчик - MouseEventHandler
Оба типа - дженерики, которым можно передать тип элемента, на котором происходит событие.
#typescript #ссылки
Статья (англ.): https://jser.dev/2023-05-31-react-types-in-typescript/
Автор статьи сделал подборку типов, используемых в React, чтобы нам не пришлось.
1. ReactElement
Главный "строительный" метод React - React.createElement(). Он принимает конфиг элемента, который нужно создать - его и описывает интерфейс ReactElement.
interface ReactElement {
type: T,
props: P,
key: Key | null,
}
ReactElement или JSX.Element (то же самое, просто алиас) - это то, что должно быть возвращено из JSXElementConstructor (из функционального или классового компонента).
2. ReactNode
Это "надтип" для ReactElement, как и в DOM - есть ноды (включают комментарии и текстовые узлы), а есть их подмножество - элементы.
В тип ReactNode входят ReactElement, строки, числа, булевы значения, фрагменты, порталы и даже null и undefined
3. FunctionComponent
Интерфейс, описывающий функциональный компонент
4. RefObject и MutableRefObject
Типы, описывающие рефы, созданные хуком
useRef
. У
useRef
есть несколько перезагрузок и одна из них приводит к тому, что поле ref.current
становится readonly
и его нельзя изменить 😳5. ComponentProps
Обобщенный тип, позволяющий "извлечь" из типа компонента его пропсы. Под капотом использует infer.
6. Dispatch и SetStateAction
Эти типы описывают самый популярный хук
useState
.Тип
Dispatch
- это просто функция, которая принимает аргумент заявленного типа и ничего не возвращает.SetStateAction
- это либо новое состояние, либо функция, которая принимает старое состояние и возвращает новое.7. События
С типизацией событий в React всегда сложно. Есть два подхода:
- типизировать само событие (SyntheticEvent), которое приходит в обработчик в виде аргумента, например, MouseEvent
- или типизировать сам обработчик - MouseEventHandler
Оба типа - дженерики, которым можно передать тип элемента, на котором происходит событие.
#typescript #ссылки
jser.dev
React types in TypeScript
Demystify the common React types in TypeScript
👍3
Вариантность и совместимость типов в TypeScript
Попробуем разобраться, что такое ковариантность и контравариантность и на что они влияют в TypeScript.
Подтип и супертип
Сначала определим основные понятия - подтип и супертип.
Подтип расширяет супертип.
⁃ Dog - это подтип, Animal - это супертип.
⁃ String - это подтип, Object - это супертип.
⁃ number - это подтип, any - это супертип.
Мы пишем, что подтип меньше супертипа (SubType <: SuperType), однако по факту, в подтипе больше информации, чем в супертипе, потому что подтип буквально расширяет супертип. Подтип «избыточен» по сравнению с супертипом.
Любое значение с типом SubType всегда является одновременно значением типа SuperType, так как имеет все необходимые для SuperType поля.
Структурная типизация
Важно понимать, что в TypeScript подтип и супертип необязательно связаны отношениями наследования (class Dog extends Animal). TypeScript реализует структурную типизацию и ориентируется только на структуру типов.
Типы Animal и Dog никак не связаны между собой, но Dog все равно является подтипом для Animal.
Ковариантность как основная стратегия
Когда мы пытаемся присвоить значение какой-то переменной в TypeScript, компилятор смотрит, а соответствует ли тип этого значения объявленному типу этой переменной, совместимы ли они, можно ли положить это значение в эту переменную.
Есть конкретные правила для определения совместимости. В большинстве случаев верно утверждение:
⁃ Вы можете безопасно использовать подтип там, где ожидается супертип.
Довольно просто понять, почему так сделано - значение с типом SubType также является значением типа SuperType, поэтому тут нет противоречий. Если программа готова справиться с Animal (супертип), значит, она справится и с Dog (подтип), ведь он предоставляет те же самые данные.
Такая стратегия называется Ковариантностью. Она разрешает «избыточность» типа и запрещает «недостаточность».
Контравариантность для параметров функций
Стратегия ковариантности действует везде, кроме одного места - определения совместимости функций.
Казалось бы, Foo2 является подтипом для Foo1 (Foo2 <: Foo1), а значит функцию типа Foo2 должно быть можно положить в переменную с типом Foo1:
Но мы получаем ошибку. При этом наоборот все работает:
Здесь тоже несложно понять, почему так. Программа ожидает функцию с одним аргументом и передает ей только один аргумент. Если на этом месте окажется функция, ожидающая больше аргументов, она их просто не получит.
В обратную сторону тоже все хорошо. Даже если программа ожидает функцию с двумя аргументами и передает два аргумента, а в сигнатуре функции указан лишь один, ничего не сломается. Функция получит свой аргумент, а второй - ненужный - просто проигнорирует.
Такая стратегия называется «контравариантность». Она разрешает «недостаточность» типа и запрещает «избыточность».
#typescript
Попробуем разобраться, что такое ковариантность и контравариантность и на что они влияют в TypeScript.
Подтип и супертип
Сначала определим основные понятия - подтип и супертип.
Подтип расширяет супертип.
⁃ Dog - это подтип, Animal - это супертип.
⁃ String - это подтип, Object - это супертип.
⁃ number - это подтип, any - это супертип.
Мы пишем, что подтип меньше супертипа (SubType <: SuperType), однако по факту, в подтипе больше информации, чем в супертипе, потому что подтип буквально расширяет супертип. Подтип «избыточен» по сравнению с супертипом.
Любое значение с типом SubType всегда является одновременно значением типа SuperType, так как имеет все необходимые для SuperType поля.
Структурная типизация
Важно понимать, что в TypeScript подтип и супертип необязательно связаны отношениями наследования (class Dog extends Animal). TypeScript реализует структурную типизацию и ориентируется только на структуру типов.
type Animal = {
name: string
}
type Dog = {
name: string
breed: string
}
Типы Animal и Dog никак не связаны между собой, но Dog все равно является подтипом для Animal.
Ковариантность как основная стратегия
Когда мы пытаемся присвоить значение какой-то переменной в TypeScript, компилятор смотрит, а соответствует ли тип этого значения объявленному типу этой переменной, совместимы ли они, можно ли положить это значение в эту переменную.
Есть конкретные правила для определения совместимости. В большинстве случаев верно утверждение:
⁃ Вы можете безопасно использовать подтип там, где ожидается супертип.
let a: any = 42 // number <: any
let b: Animal = new Dog() // Dog <: Animal
Довольно просто понять, почему так сделано - значение с типом SubType также является значением типа SuperType, поэтому тут нет противоречий. Если программа готова справиться с Animal (супертип), значит, она справится и с Dog (подтип), ведь он предоставляет те же самые данные.
Такая стратегия называется Ковариантностью. Она разрешает «избыточность» типа и запрещает «недостаточность».
Контравариантность для параметров функций
Стратегия ковариантности действует везде, кроме одного места - определения совместимости функций.
type Foo1 = (param: number) => void
type Foo2 = (param1: number, param2: string) => void
Казалось бы, Foo2 является подтипом для Foo1 (Foo2 <: Foo1), а значит функцию типа Foo2 должно быть можно положить в переменную с типом Foo1:
let foo1: F1 = (param1: number, param2: string) => {} // Error
Но мы получаем ошибку. При этом наоборот все работает:
let foo2: F2 = (param1: number) => {} // Ok
Здесь тоже несложно понять, почему так. Программа ожидает функцию с одним аргументом и передает ей только один аргумент. Если на этом месте окажется функция, ожидающая больше аргументов, она их просто не получит.
В обратную сторону тоже все хорошо. Даже если программа ожидает функцию с двумя аргументами и передает два аргумента, а в сигнатуре функции указан лишь один, ничего не сломается. Функция получит свой аргумент, а второй - ненужный - просто проигнорирует.
Такая стратегия называется «контравариантность». Она разрешает «недостаточность» типа и запрещает «избыточность».
#typescript
👍3🌭1
Как устроена система типов в TypeScript
Статья (рус.): https://ru.hexlet.io/blog/posts/sistema-tipov-v-typescript
В статье разбирается стратегия ковариантности типов на основе принципе подстановки Барбары Лисков: поведение подтипа не должно противоречить поведению супертипа.
Объясняется, что подтип более строгий, чем супертип, так как ему соответствует меньше значений (собственно поэтому SubType < SuperType).
Немного говорится об иерархии типов в TypeScript, особенностях типов any, unknown, never и void.
Приводится простой способ проверить соответствие:
Статья также рассказывает о двух видах приведения типов:
⁃ восходящем (безопасное приведение подтипа к супертипу, происходит неявно)
⁃ нисходящее (приведение супертипа к подтипу, должно быть явным)
Обычно восходящее приведение происходит неявно, автоматически, но есть две ситуации, в которых оно запрещено - при работе с литеральными объектами (которые создаются на месте использования).
В общем, хорошая статья, подводящая под довольно сложную тему хороший теоретический базис.
#typescript
Статья (рус.): https://ru.hexlet.io/blog/posts/sistema-tipov-v-typescript
В статье разбирается стратегия ковариантности типов на основе принципе подстановки Барбары Лисков: поведение подтипа не должно противоречить поведению супертипа.
Объясняется, что подтип более строгий, чем супертип, так как ему соответствует меньше значений (собственно поэтому SubType < SuperType).
Немного говорится об иерархии типов в TypeScript, особенностях типов any, unknown, never и void.
Приводится простой способ проверить соответствие:
type A = string extends unknown ? true : false // true
type B = unknown extends string ? true : false // false
Статья также рассказывает о двух видах приведения типов:
⁃ восходящем (безопасное приведение подтипа к супертипу, происходит неявно)
⁃ нисходящее (приведение супертипа к подтипу, должно быть явным)
Обычно восходящее приведение происходит неявно, автоматически, но есть две ситуации, в которых оно запрещено - при работе с литеральными объектами (которые создаются на месте использования).
В общем, хорошая статья, подводящая под довольно сложную тему хороший теоретический базис.
#typescript
Хекслет
Как устроена система типов в TypeScript
Перевели большую статью бывшего разработчика Amazon Web Services Хэ Чжэнхао и узнали, что такое иерархия типов в TypeScript и как они соотносятся между собой.
👍3
TypeScript: Защитники типов (Type Guards)
Когда мы работаем с объединениями (union) в TypeScript, часто возникает необходимость совершить разные действия в зависимости от того, какой конкретно тип пришел.
Эта логика обычно реализуется с помощью разнообразных условий и проверок. Эти условия пишутся на JavaScript, но TypeScript умеет понимать некоторые из этих конструкций. То есть, если правильно написать проверку, то внутри блока if компилятор TypeScript будет понимать, что работает уже с уточненным типом.
Такие проверочные конструкции, которые понятны TS, называются «защитниками типа» - Type Guards. Они позволяют «сузить тип», выбрать нужный из объединения.
1. На основе типа данных
TypeScript понимает операторы
Эти операторы отлично распознаются компилятором внутри условий if-else, а также внутри тернарного оператора. Но не распознаются внутри конструкции switch.
2. С использование Tagged Union
Tagged Union (размеченное объединение) или Discriminated Union (дискриминантное объединение) - это объединение типов, у которых есть специальное общее поле со значением специфичным для конкретного типа. По этому полю эти типы можно различить.
Не имеет значения, как называется дискриминант, главное, чтобы он однозначно определял тип - TypeScript это понимает:
Такая проверка будет работать в любом условии: и в if-else, и в тернарном операторе, и даже в switch.
3. По наличию публичного поля
Почти то же самое, что и предыдущий пункт, но тут мы проверяем не значение поля, а его наличие - с помощью оператора
4. Функция-предикат
И наконец последняя (самая мощная) конструкция, которая может сузить объединение типов и которую может распознать TypeScript - это функция, которая возвращает предикат. Предикат - это однозначное утверждение, что значение, переданное этой функции, принадлежит к конкретному типу.
Такая функция оформляется особым образом - с помощью ключевого слова
Функция принимает параметр
Проверка внутри функции может быть абсолютно любая - TypeScript это не волнует. Нужно только, чтобы функция вернула логическое значение - true или false. Таким образом, ответственность за определение типа полностью перекладывается на разработчика.
Параметров тоже может быть сколько угодно, главное, чтобы один из них фигурировал в сигнатуре предиката.
#typescript
Когда мы работаем с объединениями (union) в TypeScript, часто возникает необходимость совершить разные действия в зависимости от того, какой конкретно тип пришел.
function move(obj: Dog | Fish | Bird) {
if (obj.type === ‘dog’) obj.run()
else if (obj.type === ‘fish’) obj.swim()
else obj.fly()
}
Эта логика обычно реализуется с помощью разнообразных условий и проверок. Эти условия пишутся на JavaScript, но TypeScript умеет понимать некоторые из этих конструкций. То есть, если правильно написать проверку, то внутри блока if компилятор TypeScript будет понимать, что работает уже с уточненным типом.
function move(obj: Dog | Fish | Bird) {
if (obj.type === ‘dog’) {
// Здесь TS уже уверен, что работает именно с Dog
obj.run()
}
// …
}
Такие проверочные конструкции, которые понятны TS, называются «защитниками типа» - Type Guards. Они позволяют «сузить тип», выбрать нужный из объединения.
1. На основе типа данных
TypeScript понимает операторы
instanceof
и typeof
.
function foo(param: number | string) {
if (typeof param === ‘string’) {
param.toUpperCase()
} else {
param.toFixed(2)
}
function move(obj: Dog | Fish | Bird) {
if (obj instanceof Dog) obj.run()
else if (obj instanceof Fish) obj.swim()
else obj.fly()
}
Эти операторы отлично распознаются компилятором внутри условий if-else, а также внутри тернарного оператора. Но не распознаются внутри конструкции switch.
2. С использование Tagged Union
Tagged Union (размеченное объединение) или Discriminated Union (дискриминантное объединение) - это объединение типов, у которых есть специальное общее поле со значением специфичным для конкретного типа. По этому полю эти типы можно различить.
class Bird {
type: ‘bird’ = ‘bird’
}
class Fish {
type: ‘fish’ = ‘fish’
}
Не имеет значения, как называется дискриминант, главное, чтобы он однозначно определял тип - TypeScript это понимает:
function move(obj: Dog | Fish | Bird) {
if (obj.type === ‘dog’) obj.run()
else if (obj.type === ‘fish’) obj.swim()
else obj.fly()
}
Такая проверка будет работать в любом условии: и в if-else, и в тернарном операторе, и даже в switch.
3. По наличию публичного поля
Почти то же самое, что и предыдущий пункт, но тут мы проверяем не значение поля, а его наличие - с помощью оператора
in
.
class Author {
public book: string = ‘Odyssey’
}
class Artist {
public painting: string = ‘Mona Lisa’
}
function getMasterpiece(creator: Author | Artist) {
let masterpiece;
if (‘book’ in creator) masterpiece = creator.book;
else masterpiece = creator.painting;
}
4. Функция-предикат
И наконец последняя (самая мощная) конструкция, которая может сузить объединение типов и которую может распознать TypeScript - это функция, которая возвращает предикат. Предикат - это однозначное утверждение, что значение, переданное этой функции, принадлежит к конкретному типу.
Такая функция оформляется особым образом - с помощью ключевого слова
is
:
function isDog(obj: Dog | Fish | Bird): obj is Dog {
return obj.type === ‘dog’
}
Функция принимает параметр
obj
и после проведения проверки утверждает, принадлежит ли obj
к типу Dog
.Проверка внутри функции может быть абсолютно любая - TypeScript это не волнует. Нужно только, чтобы функция вернула логическое значение - true или false. Таким образом, ответственность за определение типа полностью перекладывается на разработчика.
Параметров тоже может быть сколько угодно, главное, чтобы один из них фигурировал в сигнатуре предиката.
function move(obj: Dog | Fish) {
if (isDog(obj)) {
obj.run()
} else {
obj.swim()
}
}
#typescript
👍3🔥2
Чем полезен тип unknown?
Статья (англ.): https://michaeluloth.com/programming-types-unknown-why-useful/
Автор статьи напоминает нам, что мы не всегда можем быть уверены в типе данных, которые приходят из какого-то внешнего источника (пользовательский ввод или api). И советует использовать для таких данных тип unknown до тех пор, пока они не пройдут явную валидацию.
Такой подход позволяет избежать ряда ошибок, например, мы не сможем использовать метод .toUpperCase, пока не докажем компилятору, что это строка.
Пример не самый идеальный и в целом можно решать проблему неожиданных типов другими путями (например, использовать try-catch), но эта статья делает две хорошие вещи:
- раскрывает сущность типа unknown
- напоминает, что нельзя доверять чужим данным
#ссылки #typescript
Статья (англ.): https://michaeluloth.com/programming-types-unknown-why-useful/
Автор статьи напоминает нам, что мы не всегда можем быть уверены в типе данных, которые приходят из какого-то внешнего источника (пользовательский ввод или api). И советует использовать для таких данных тип unknown до тех пор, пока они не пройдут явную валидацию.
// не доверяем пришедшим данным
const getUserInput = (): unknown => {/*...*/}
const safe = () => {
const data = getUserInput()
if (typeof data === 'string') { // явно валидируем
data.toUpperCase() // используем метод строки
} else {
// обрабатываем некорректный тип
}
}
Такой подход позволяет избежать ряда ошибок, например, мы не сможем использовать метод .toUpperCase, пока не докажем компилятору, что это строка.
Пример не самый идеальный и в целом можно решать проблему неожиданных типов другими путями (например, использовать try-catch), но эта статья делает две хорошие вещи:
- раскрывает сущность типа unknown
- напоминает, что нельзя доверять чужим данным
#ссылки #typescript
Michael Uloth
Why Unknown Types Are Useful
Sometimes you want the type checker to help you avoid making assumptions.
👍6