Шпаргалка по React с TypeScript

Шпаргалка по React с TypeScript

От автора: благодаря этому руководству вы узнаете о наиболее распространенных типах, которые могут понадобиться при разработке приложения React-TypeScript.

Как типизировать React props

Поскольку React props используются для отправки данных от одного компонента React в другой, существует множество типов, которые вы можете использовать для типизации props. Чтобы записать типы props, нужно добавить двоеточие и буквенное обозначение (: {}) рядом с деструктурирующим назначением дочерних props в объявлении компонента React. Вот пример типизации string и number:

Создание алиаса для props

Поскольку в React принято записывать один компонент в один файл .js или .jsx, вы можете объявить алиас type для props компонента, чтобы упростить чтение кода. Вот пример создания алиаса type для props компонента App:

Как видите, type для компонента props избавит вас от необходимости включать типы props в одну строку.

Типизация дополнительных props

Вы можете сделать props необязательными, добавив символ вопросительного знака «?» после имени props. В следующем примере props для title становятся необязательными:

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

Список типов для props компонента React

Теперь, когда вы знаете, как проверить тип props, вот список общих типов, которые вы можете использовать в своем приложении React. Во-первых, у вас есть примитивные типы, такие как string, number и boolean, как показано ниже:

Вы также можете создать массив одного типа, добавив буквенное обозначение массива ([]) после типа следующим образом:

Также, вы можете указать значения, которые могут быть приняты для props. Вам нужно разделить литералы с помощью оператора вертикальной черты «|» как показано ниже:

TypeScript выдаст статическую ошибку, если указанное выше значение priority или score не соответствует ни одному из литеральных значений. Также вы можете добавить объект в props следующим образом:

Если у вас есть массив объектов, просто добавьте нотацию массива в конце объявления следующим образом:

React props также могут иметь такие функции, как onClick и onChange. Вы можете типизировать параметры, принимаемые функцией, или взять объект event из HTML, как показано ниже:

Если вы объявляете функцию onChange в теле компонента, вы можете сразу же проверить параметр и типы возвращаемых значений, как показано ниже:

Наконец, компоненты React могут принимать другой компонент в качестве дочерних props, поэтому вам нужно использовать ReactNode для типизации этих дочерних props:

И это наиболее распространенные типы, которые вы можете использовать для React props. Давайте научимся типизировать функциональные компоненты React!

Как типизировать функциональные компоненты React

Библиотека TypeScript’s Definitely Typed включект React.FunctionComponent (или React.FC для краткости), которые можно использовать для типизации функциональных компонентов React.

Вы можете комбинировать type Props и тип React.FC, чтобы создать типобезопасный функциональный компонент props следующим образом:

Когда вы вызываете компонент App, вам нужно будет указать message с типом string. Но поскольку TypeScript может определить тип вашей переменной, вы можете убрать типизацию компонента с помощью React.FC следующим образом:

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

Благодаря функции предполагаемого типа TypeScript вам вообще не нужно типизировать функциональные компоненты React.

Как типизировать хуки React

Хуки React поддерживаются библиотекой @types/react начиная с версии 16.8. Как правило, Typescript должен иметь возможность задать тип для ваших хуков, если у вас нет особых случаев, когда тип должен быть объявлен явно. Давайте посмотрим, как типизировать хуки React, и начнем с хука useState.

Типизация хука useState

Значение useState может быть определено из начального значения, которое вы устанавливаете при вызове функции.
Например, следующий вызов useState() инициализирует состояние пустой строкой. При вызове функции setState нужно передать строку или будет ошибка:

Но когда вам нужно инициализировать состояние такими значениями, как null или undefined, тогда нужно добавить generic при инициализации состояния. Generic позволяет использовать несколько типов для хука useState, как показано ниже:

Когда у вас есть сложный объект в качестве значения состояния, вы можете создать interface или type для этого объекта следующим образом:

Вот так вы можете типизировать хуки useState в своем приложении.

Типизация хуков useEffect и useLayoutEffect

Вам не нужно типизировать хуки useEffect и useLayoutEffect, поскольку они не имеют возвращаемого значениями. Функция очистки для хука useEffect также не имеет значения, которое можно изменить. Вы можете писать эти хуки как обычно.

Типизация хука useContext

Тип хука useContext обычно определяется из начального значения, которое вы передали в функцию createContext() следующим образом:

Приведенное выше значение контекста будет выведено как следующий объект:

В качестве альтернативы вы также можете создать type, который будет служить универсальным для возвращаемого значения CreateContext. Например, предположим, что у вас есть ThemeContext, который имеет только два значения: light и dark. Вот как вы типизируете контекст:

Тип будет использоваться в вашем коде позже, когда вы установите значение контекста с помощью ThemeContext.Provider. Затем хук useContext определит тип из объекта контекста ThemeContext, который вы передали в качестве аргумента:

Типизация хука useRef

Основываясь на документации React, хук useRef обычно используется для ссылки на input элемент HTML следующим образом:

Вы можете написать общий вариант использования, который принимает HTMLInputElement, как показано ниже:

Вам не нужно добавлять null к типу дженерика, потому что HTMLInputElement принимает уже одно из двух значений: HTMLInputElement | null.

Типизация хука useMemo

Хук useMemo возвращает мемоизированное значение, поэтому тип будет определятся возвращенным значением:

Типизация хука useCallback

Хук useCallback возвращает мемоизированную функцию обратного вызова, поэтому тип будет определятся из значения, возвращаемого функцией обратного вызова:

Типизация пользовательских хуков

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

Когда вы возвращаете массив, подобно как в useState, вам нужно указать возвращаемое значение как const, чтобы TypeScript не типизировал ваш тип как объединение:

Без указания const -TypeScript будет типизировать возвращаемые значения как (string | boolean) [] вместо [string, boolean]

Вот как можно типизировать хуки React. Давайте теперь узнаем, как типизировать HTML-события и формы.

Типизация HTML-событий и форм

TypeScript может правильно определить большинство типов событий HTML, поэтому вам не нужно явно указывать тип. Например, событие onClick элемента кнопки будет определено TypeScript как React.MouseEvent:

Для HTML-форм вам нужно будет указать тип onSubmit как React.FormEvent, потому что интерфейс по умолчанию Any выдаст ошибку. Вот пример формы React в TypeScript:

Понимание различных типизаций для компонентов React

Хотя TypeScript может определить тип возвращаемого значения функциональных компонентов React, у вас может быть проект с правилом линтинга, которое требует, чтобы тип возвращаемого значения был явно определен. Библиотека @types/react имеет несколько типов, которые вы можете использовать для определения типа возвращаемого значения функциональных компонентов React. Вот они: ReactElement, JSX.Element,ReactNode.

Этот раздел посвящен тому, чтобы помочь вам разобраться в этих типах и в том, когда их использовать.
ReactElement — это интерфейс для объекта с типом, props и ключевыми свойствами, как показано ниже:

JSX.Element — это расширение ReactElement, в котором реализованы тип <T> и свойства <P>, как вы можете увидеть в репозитории:

Тип для ReactElement более строгий, чем в JSX.Element, но по сути они такие же. Наконец, ReactNode — это очень свободный тип, поскольку он включает все, что может быть возвращено методом render() компонентов класса React. В репозитории ReactNode определяется так:

Вот почему, когда ваш компонент имеет дочерние props, которые может получать другой компонент, рекомендуется использовать ReactNode в качестве типа, потому что он может получать все, что может быть отображено с помощью React.

С другой стороны, ReactElement и JSX.Element более строги по сравнению с ReactNode, поскольку не позволяют возвращать такие значения, как null.

Когда использовать каждый тип?

Тип ReactNode лучше всего использовать для типизации дочерних props, которые могут получать другой компонент React или элементы JSX, например:

Это связано с тем, что оба типа ReactElement и JSX.Element более строги к типу возвращаемого значения (не допускают null) и ожидают, что вы вернете один элемент.

Чтобы принять как один, так и несколько дочерних элементов для этих двух типов, вам необходимо использовать ReactElement | ReactElement [] или JSX.Element | JSX.Element [] как дочерний тип.

Типы ReactElement и JSX.Element больше подходят для явного определения типа возвращаемого значения компонента React следующим образом:

Но поскольку мы говорим здесь о лучших практиках, я рекомендую вам следовать определению интерфейса FunctionComponent в библиотеке типов, в котором используется ReactElement <any, any> | null:

И поскольку JSX.Element в точности расширяет ReactElement <any, any>, вы можете определить тип возвращаемого значения функционального компонента React следующим образом:

Таким образом, ваш компонент по-прежнему может ничего не отображать, возвращая null. Я надеюсь, что этот раздел помог вам понять различные типы, которые можно использовать для типизации компонентов React.

Как типизировать (расширять) HTML-элементы

Иногда вам нужно создать небольшой модульный компонент, который принимает атрибуты собственного HTML-элемента в качестве свойств.

Некоторые полезные компоненты, которые вы можете создать для своего приложения, — это button, img или input. Библиотека @types/response поставляется с типом ComponentPropsWithoutRef, который вы можете использовать для получения всех собственных атрибутов HTML-элемента в качестве типа для props вашего компонента.

Например, элемент button уже знает об собственном атрибуте onClick, но когда вы создаете компонент React <Button>, вам нужно определить props, используя интерфейс или такой тип:

В приведенном выше примере вам нужно добавить еще один props в ButtonProps, как показано ниже:

Можно использовать тип ComponentPropsWithoutRef, так что вам не нужно добавлять эти собственные атрибуты HTML к типу по мере роста вашего приложения. Вы можете создать тип, который имеет все атрибуты button в виде таких свойств:

Тип ComponentPropsWithoutRef <«button»> имеет все props элемента HTML button. Если вы хотите создать компонент <Img>, вы можете использовать тип ComponentPropsWithoutRef <«img»>:

Вам нужно только изменить общий тип ComponentPropsWithoutRef <T>, чтобы расширить различные элементы HTML. Например:

ComponentPropsWithoutRef <‘img’> для расширения элемента <img>

ComponentPropsWithoutRef <‘button’> для расширения элемента <button>

ComponentPropsWithoutRef <‘a’> для расширения элемента <a>

И так далее. Когда вам нужно добавить пользовательский prop, которого нет в HTML-элементе, вы можете создать интерфейс, расширяющий собственные атрибуты, следующим образом:

Это особенно полезно, если вам нужен специальный prop для определения внешнего вида вашего компонента. В следующем примере пользовательский prop color используется для определения атрибута CSS style:color элемента h1:

Тип ComponentPropsWithoutRef упрощает создание компонента, который является расширением элементов HTML, без необходимости самостоятельно вводить все возможные параметры prop. Вы даже можете добавить дополнительные props, расширив интерфейс.

Интерфейс ComponentPropsWithoutRef также имеет двойника под названием ComponentPropsWithRef, который вы можете использовать, когда нужно перенаправить ссылку на дочерние элементы. Узнайте больше о переадресации ссылок здесь.

ComponentPropsWithoutRef против [Element] HTMLAttributes

Если вы раньше использовали TypeScript в React, возможно, вы знакомы с интерфейсом [Element] HTMLAttributes из библиотеки @types/react, который можно использовать для расширения HTML-элементов следующим образом:

Интерфейсы [Element]HTMLAttributes создают тот же тип, что и интерфейс ComponentPropsWithoutRef, но они более подробны, поскольку вам нужно использовать другой интерфейс и дженерик для каждого элемента HTML.

С другой стороны, ComponentPropsWithoutRef требует, чтобы вы изменили только общий тип <T>. Оба подходят для расширения HTML-элементов в компонентах React. Вы можете увидеть объяснение автора библиотеки здесь.

Когда использовать type и interface?

И type, и interface в TypeScript могут использоваться для определения свойств, компонентов и хуков React. Из справочника по TypeScript:

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

При использовании интерфейсов вы можете свободно расширять его следующим образом:

Но типы нельзя расширять, как интерфейсы. Вам необходимо использовать символ пересечения (&) следующим образом:

Далее, объявление интерфейса всегда является объектом, а объявление типа может иметь примитивные значения, как показано ниже:

Ни один из приведенных выше примеров невозможен с интерфейсом, поэтому тип может быть предпочтительным для простых значений объекта. Вопрос в том, когда использовать одно вместо другого? Снова из Руководства по TypeScript: Если вам нужна эвристика, используйте interface, пока вам не понадобится использовать функции type.

Анализатор кода TypeScript сообщит вам, когда вам нужно использовать interface или type. Если вы не уверены, какой из них использовать, всегда выбирайте interface, пока не увидите причину использования type. Если вам нужна дополнительная информация, вот ответ StackOverflow, в котором сравниваются interface и type.

Надеюсь, эта шпаргалка будет полезна для вашего следующего проекта.

Автор: Nathan Sebhastian

Источник: blog.bitsrc.io

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии запрещены.