React Junior
207 subscribers
37 photos
462 links
Изучение React с нуля
加入频道
Своими словами:
в этих типах мы используем обобщения (дженерики).

Например, утилита Partial принимает некий тип T, неизвестно, какой конкретно, и на его основе создает новый тип.

Она берет все ключи исходного типа (keyof T) и делает их своими ключами. Каждый конкретный ключ обозначается типом P. То есть P - это каждый ключ типа T, и у нового типа будут те же самые поля.

Но к каждому полю добавлен значок ? - то есть поле становится опциональным, необязательным.

А типы полей ровно те же самые, что и у исходного типа - T[P]. Это обычный синтаксис доступа к свойствам объекта, но тут он применяется к типу.

В итоге получается точно такая же структура, но каждое поле в ней необязательное.

#typescript
👍2🔥1
Typescript. Утилиты. Часть 2 (Exclude, Extract, NonNullable)

Первая часть (Readonly, Required, Partial): https://yangx.top/react_junior/413

Exclude

Принимает два параметра:
- Union
- ExcludedMembers - члены, которые нужно исключить из Union

Результатом является объединение, в которое входят все члены Union, кроме тех, которые могут быть присвоены в ExcludedMembers

Extract

Принимает два параметра:
- Type
- Union - объединение типов, которые нужно отобрать из Type

Результатом является объединение, в которое входят все члены Type, которые одновременно могут быть присвоены в Union

NonNullable

Принимает один параметр Type и выбрасывает из него null и undefinded.

#typescript
👍2🔥1
Typescript. Утилиты. Часть 3 (Parameters, ReturnType)

Первая часть (Readonly, Required, Partial): https://yangx.top/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://yangx.top/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).

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

Общий синтаксис условных типов выглядит так:

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

Статья подробно рассказывает об операторе & в 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 для пропсов компонента.


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
👍3👎1
Typescript. Утилиты. Часть 4 (Uppercase, Lowercase, Capitalize, Uncapitalize)

Первая часть (Readonly, Required, Partial): https://yangx.top/react_junior/413
Вторая часть (Exclude, Extract, NonNullable): https://yangx.top/react_junior/429
Третья часть (Parameters, ReturnType): https://yangx.top/react_junior/430

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

- Uppercase
- Lowercase
- Capitalize
- Uncapitalize

#typescript
🔥2
TypeScript. Ключевое слово infer

Весь вечер пытаюсь разобраться с ключевым словом infer в TypeScript 🙂 Не сказать, что концепция самая очевидная, но вроде и не чрезмерно сложная, если я, конечно, все правильно понимаю.

Итак, infer может "выводить" один тип на основании другого. Использовать это ключевое слово можно только в условных конструкциях вместе с extend. Выведенный тип затем можно использовать, например, вернуть из условной конструкции.

Подробнее об условных типах: https://yangx.top/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
👍4