Функциональные компоненты¶
Поскольку создавать React приложения рекомендуется на основе функциональных компонентов, то именно с них и начнется наше погружение в типизированные .tsx
конструкции.
Всем известно, что React компоненты, обозначаемые как функциональные, являются обычными функциями. И как все функции в JavaScript, они также могут быть определены двумя способами — в виде обычной функции (Function Declaration) и в виде функционального выражения (Function Expression), таящего один неочевидный нюанс, который подробно будет рассмотрен по ходу знакомства с ним.
Определение компонента как Function Declaration¶
Типизация параметров¶
Факт, что функциональный компонент, является обычной функцией, предполагает необходимость в типизировании её сигнатуры или точнее её параметров, так как указание типа возвращаемого значения не просто можно, а даже рекомендуется опустить, возложив эту работу на вывод типов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Также необходимо всегда помнить, что независимо от того используется пространство имен React
непосредственно или нет, модули определяющие React компоненты обязаны его импортировать. В противном случае компилятор напомнит об этом с помощью ошибки.
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 |
|
При определении первого параметра функционального компонента props
появляется потребность в типе описывающем их.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Поскольку идеология React подразумевает прокидывание пропсов из одного компонента в другой, то компоненту выступающему в роли провайдера помимо своих пропсов, необходимо описывать пропсы своих детей. В случаях, когда в проброске нуждаются только несколько значений принадлежащих к типам из системы типов TypeScript, декларирование их в пропсах провайдера не будет выглядеть удручающе.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Экспорт типа параметров¶
Но если пробрасываемые пропсы представлены множеством значений, к тому же, частично или полностью принадлежат к пользовательским типам, то более целесообразно включить в описание типа пропсов компонента-провайдера, тип, описывающий пропсы компонента, которому они предназначаются. Поэтому тип описывающий пропсы желательно всегда экспортировать. Для того, чтобы избежать коллизий именования типов представляющих пропсы, их идентификаторы необходимо конкретизировать, то есть давать более уникальные имена. Поэтому принято имени Props
добавлять префикс идентичный названию самого компонента.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
В случаях когда компонент-провайдер нуждается только в части пропсов определенных в типе представляющих их, ненужную часть можно исключить с помощью типа Omit<T, K>
или Exclude<T, U>
.
Получение типа параметров без его экспорта¶
Тем, кому ближе минимализм, может прийтись по душе подход с получением типа пропсов без его экспорта.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Подобный способ будет не заменим при работе со сторонними библиотеками React компонентов, которые не имеют экспорты типов описывающих свои пропсы.
Модификатор readonly для параметров¶
Не будет лишним напомнить, что при помощи модификатора readonly
не удастся избежать изменений переменных ссылки на которые были получены с помощью механизма деструктуризации.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Такое поведение является причиной того, что деструктурированные идентификаторы являются определением новой переменной, а переменные не могут иметь модификатор readonly
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Декларирование children¶
При необходимости декларирования children
можно выбрать несколько путей. Первый из них подразумевает использование обобщенного типа PropsWithChildren<P>
ожидающего в качестве аргумента типа тип представляющий пропсы. Данный тип определяет children
как необязательное поле принадлежащее к ReactNode
. При отсутствии продуманного плана на счёт children
или необходимости их принадлежности к любому допустимому типу, данный тип будет как нельзя к месту.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Если логика компонента предполагает обязательную установку children
или уточнение типа к которому они принадлежат, то появляется необходимость их непосредственной декларации в типе представляющем пропсы этого компонента.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Может показаться, что конкретизация типа children
будет полезна при создании собственных ui
компонентов. К примеру при создании компонента List
выполняющего отрисовку элемента ul
, было бы здорово определить children
, как массив компонентов ListItem
отрисовывающих элемент li
.
Для этого понадобится импортировать обобщенный тип ReactElement<P, T>
, первый параметр типа которого ожидает тип пропсов, а второй строку или конструктор компонента для указания его в качестве типа поля type
необходимого для идентификации. По факту тип ReactElement<P, T>
представляет экземпляр любого компонента в системе типов React. После определения компонентов List
и ListItem
, для первого нам понадобится переопределить поле children
, указав ему тип ReactElement<ListItemProps>
, что буквально означает - экземпляр компонента, пропсы которого принадлежат к типу указанному в качестве первого аргумента типа.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
Если кажется просто, то не стоит сомневаться, оно так и есть. Совершенно ничего сложного. Единственное стоит уточнить два важных момента.
Первый момент заключается в том, что конкретизация типа children
для React элементов не работает. Проще говоря, если определить новый компонент Label
и указать ему в качестве пропсов тип определяющий единственное поле type
, то его экземпляр без возникновения ошибки можно будет указать в качестве children
компоненту List
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
Всё дело в том, что экземпляр компонента представляется типом Element
из пространства имен JSX, является производным от типа ReactElement<P, T>
. Кроме того, при расширении, своему базовому классу, в качестве аргументов типа, он устанавливает any
- Element extends ReactElement<any, any>
. Это в свою очередь означает? что любые экземпляры компонентов будут совместимы с любыми типами ReactElement<P, T>
, что делает уточнение типа бессмысленным.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Кроме этого, ReactElement<P, T>
совместим не только с экземплярами компонентов, но и React элементов.
1 |
|
Это, как уже было сказано, делает конкретизацию children
, для экземпляров React компонентов и элементов, бессмысленной. Остается надеяться, что это исправят.
Второй неочевидный момент состоит в том что, при текущей постановке, в случае необходимости указать в качестве children
множество экземпляров ListItem
, возникнет ошибка.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Для разрешения подобного случая необходимо указать тип children
как объединение (Union
) определяемое типами представляющих как единственный экземпляр ReactElement<ListItemProps>
так и множество, а если быть конкретнее, то массив экземпляров ReactElement<ListItemProps>[]
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Ссылки useRef() и ref¶
Ввиду того, что тема касающаяся первого параметра функционального компонента обозначаемого пропсами, себя исчерпала, пришло время рассмотреть его второй, не часто используемый, параметр, обозначаемый как реф и предназначенный для передачи ссылки на текущий компонент. Для большего понимания этого механизма необходимо начать его рассмотрение из далека. Но прежде стоит уточнить два момента.
Во-первых тему посвященную рефам стоит начать с напоминания, что они делятся на два вида. Первый вид предназначен для получения ссылок на React элементы, а второй на React компоненты. Так вот второй параметр функционального компонента предназначен для установления рефы на себя самого, тио есть на компонент.
Во-вторых, при рассмотрении механизма посвященного рефам, применяются хуки, чья логика работы будет затронута лишь поверхностно, поскольку впереди ожидает целая глава посвященная их подробному рассмотрению.
Представьте сценарий при котором форма должна перейти в начальное состояние путем вызова нативного метода reset()
что потребует получения на нее ссылки с помощью объекта рефы создаваемого хуком useRef()
.
Для начала необходимо с помощью универсальной функции useRef()
создать объект рефы и присвоить ссылку на него переменной, которую в дальнейшем установить элементу формы. Сразу стоит обратить внимание, что декларации React элементов содержат устаревшие типы в аннотации поля ref
. Это непременно приведет к возникновению ошибки при установлении объекта рефы. Чтобы этого избежать, необходимо явным образом, при определении объекта рефы, преобразовать его к обобщенному типу RefObject<T>
, которому в качестве аргумента типа установить тип нативного элемента, в данном случае HTMLFormElement
. Также стоит сделать акцент на том, что необходимо именно преобразование. Указания аннотации типа переменной или передачи типа в качестве аргумента типа, хуку не поможет. Более детально поведение хука useState()
рассматривается в главе посвященной предопределенным хукам.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Обратные ссылки forwardRef¶
Если появится необходимость задать форме первоначальное состояние извне компонента, то можно прибегнуть к механизму получения ссылки на сам компонент, или точнее на определяемый им объект выступающий в роли публичного api. Но чтобы стало возможным получить ссылку на функциональный компонент, его необходимо преобразовать с помощью универсальной функции forwardRef<R, P>()
, на которой сфокусируется дальнейшее повествование.
По факту логика работы универсальной функции forwardRef<R, P>(render)
заключатся в проверке единственного параметра на принадлежность к функциональному типу у которой помимо первого параметра представляющего props
, определен ещё и второй, представляющий ref
. Данная функция обозначается как render
и теоретически её можно считать функциональным компонентом с определением второго параметра предназначенного для установления рефы. В системе типов React функция render
принадлежит к обобщенному функциональному типу ForwardRefRenderFunction<T, P>
определяющего два параметра типа, первый из которых представляет тип рефы, а второй пропсов. Первый параметр функции render
представляющий пропсы не таит в себе ничего необычного. Вотличии от него, второй параметр представляющий рефу, требует детального рассмотрения, поскольку именно с ним связан один неочевидный момент.
Дело в том что рефы могут быть представлены как экземпляром объекта принадлежащего к типу RefObject<T>
или полностью совместимым с ним MutableRefObject<T>
, так и функцией <T>(instance: T) => void
. Учитывая этот факт, функция render
, в аннотации типа второго параметра ref
, просто вынуждена указать все эти типы в качестве union
. Но сложность состоит в том, что определение объединения происходит непосредственно в аннотации типа параметра ref
. Простыми словами система типов React не предусмотрела более удобного и короткого псевдонима типа представляющего рефу определяемую функциональным компонентом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Это означает, что функциональный компонент определенный как Function Declaration и указавший принадлежность второго параметра к типу, скажем MutableRefObject<T>
не сможет пройти проверку на совместимость типов в качестве аргумента универсальной функции forwardRef()
, даже если установить её аргументы типа. И причина тому контрвариантность параметров функции при проверке на совместимость.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
Разрешить данную ситуацию можно несколькими способами. Первый заключается в явном преобразовании типа функционального компонента к типу ForwardRefRenderFunction<T, P>
которому в качестве аргументов типа требуется указать необходимые типы. При этом отпадает нужда в указании аргументов типа непосредственно самой универсальной функции forwardRef<T, P>()
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Следующий способ заключается в получении типа представляющего рефу непосредственно из самого функционального типа ForwardRefRenderFunction<T, P>
. Для необходимо указать в аннотации второго параметра функционального компонента обобщенный тип взятого у второго параметра функционального типа ForwardRefRenderFunction<T, P>
при помощи типа Parameters<T>
предназначенного для получения массива с типами соответствующих параметрам функции. Поскольку интересующий нас тип принадлежит второму параметру, то он будет доступен как элемент под индексом один. Кроме того в указании аргументов типа универсальной функции forwardRef<T, P>()
нет необходимости, поскольку выводу типов достаточно описания сигнатуры функционального компонента.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Последнее на что стоит обратить внимание, это обобщенный тип ForwardRefExoticComponent<P>
к которому принадлежит значение возвращаемое из универсальной функции forwardRef<T, P>()
и указывать который в явной форме нет никакой необходимости.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
После того как функциональный компонент получит рефу, ему необходимо присвоить ей значение выступающее в качестве открытого api. Для этого необходимо прибегнуть к помощи хука useImperativeHandle<T, R>(ref: Ref<T>, apiFactory() => R): void
подробное рассмотрение которого можно найти в теме посвященной предопределенным хукам.
Для того чтобы ассоциировать api компонента с компонентной рефой при помощи хука useImperativeHandle()
, ему необходимо передать её в качестве первого аргумента. После этого, компонентная рефа будет ассоциирована со значением возвращаемого из функции ожидаемой хуком в качестве второго параметра. Процесс переинициализации компонентной рефы будет выполнятся всякий раз при изменении элементов массива ожидаемого в качестве третьего параметра данного хука. Также необходимо уточнить что рефа создаваемая с помощью хука useRef()
и предназначенная для ассоциации с функциональным компонентом, также нуждается в явном преобразовании к обобщенному типу MatableRefObject<T>
, которому в качестве единственного аргумента типа будет установлен тип представляющий открытое api компонента.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
|
В связи с тем, что функциональный компонент может определять только два параметра, пора перейти к рассмотрению следующего звена его сигнатуры - аннотации типа возвращаемого им значения. Для этого возвратимся к первоначальному, модифицированному с учетом пропсов, примеру функционального компонента у которого тип возвращаемого значения не указан явно, что в большинстве случаев является предпочтительней явного указания.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Система типов React¶
И дело не в том чтобы как можно больше делегировать работы выводу типов экономя тем самым драгоценное время, а в том, что система типов React, устанавливаемая из репозиториев @types
, не имеет достаточно высокого уровня типобезопастности. Поскольку это очень щекотливая тема её освещение стоит начать с самого начала, а именно с перечисления типов к которым может принадлежать возвращаемое значение.
И так, любое допустимое возвращаемое компонентом значение, в системе типов React, может быть представлено типом ReactNode
являющимся объединением (Union
) определяемого типами ReactChild | ReactFragment | ReactPortal | boolean | null | undefined
. Тип ReactChild
также представляет собой объединение типов ReactElement<Props, Type> | ReactText
. Первый, как уже было рассмотрено ранее, представляет экземпляр любого компонента и элемента React, а второй объединение string | number
. ReactFragment
представляет объединение для {} | ReactNodeArray
. Не сложно догадаться, что ReactNodeArray
, это абстракция над Array<ReactNode>
. Оставшийся тип ReactPortal
является производным от типа ReactElement
. Это может казаться очень запутанным и более того разбираться в этом прямо сейчас нет нужды, поскольку совсем скоро станет ясно, в чем кроется подвох, причиной которого являются два из перечисленных типа.
Первый тип, вносящий смуту, это ранее рассмотренный ReactElement<P, T>
и всё неожиданное поведение которое с ним связанно. Вторым типом вносящий неразбериху стал ReactFragment
, поскольку определяющий его пустой объектный тип {}
совместим с любым экземпляром объектного типа. По факту, при использовании в качестве типа возвращаемого значения ReactFragment
или ReactNode
ошибки не возникнет даже если оно будет экземпляром Promise
или чего-то ещё. И хотя отсутствие ошибки на этапе компиляции не означает, что её получится избежать во время выполнения, сам сценарий с возвратом ошибочного значения может показаться чересчур надуманным. С какой-то долей вероятности можно с этим согласится, но поскольку идеология TypeScript подразумевает выявление проблем в программах до их запуска, об этом стоило хотя бы упомянуть.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Из всего этого следует что прибегать к аннотации типа возвращаемого значения стоит только в случаях когда оно принадлежит к number
, string
, boolean
, null
или массиву элементы которого принадлежат к оному из четырех перечисленных типов. Да и то при острой необходимости. В остальных случаях целесообразней возложить эту работу на вывод типов, для которого это обычное дело.
Типы событий React¶
Последнее что осталось без внимания, это событийный механизм или если быть точнее определение слушателей событий. Для этого в системе типов React определен специальный обобщенный тип ReactEventHandler<T>
ожидающий в качестве аргумента типа тип представляющий нативный dom элемент которому будет установлен текущий слушатель событий.
Представим сценарий в котором по нажатию на кнопку с типом submit
необходимо вернуть первоначальные значения элементов формы. Для этого потребуется подписать элемент формы на событие submit
и по его возникновению вызвать у нативного элемента формы, ссылка на которую доступна через свойство событийного объекта target
, метод reset
.
Первым делом реализация подобного сценария потребует импорта обобщенного типа ReactEventHandler<T>
, который в качестве аргумента типа получит тип нативного dom элемента HTMLFormElement
, после чего будет указан в аннотации слушателя событий form_submitHandler
. Выбор типа нативного dom элемента, в данном случае HTMLFormElement
, обуславливается типом элемента, которому устанавливается слушатель событий, в данном случае <form>
.
Стоит также обратить внимание что единственный параметр слушателя событий в аннотации типа не нуждается, поскольку вывод типов опирается на обобщенный тип ReactEvenHandler<T>
.
По возникновению события, первым делом необходимо предотвратить поведение по умолчанию, чтобы избежать перезагрузки вкладки браузера. Поскольку ссылка на нативную форму доступна через определенное в объекте события свойство target
, которое принадлежит к типу EventTarget
, то перед присвоением её переменной form
появляется необходимость в приведении к типу HTMLFormElement
с помощью оператора as
. После это можно вызывать нативный метод reset
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Несмотря на то что такой способ типизирования слушателей событий является предпочтительным, также не будет лишним рассмотреть и другой имеющийся вариант состоящий в описании непосредственно сигнатуры функции.
Для этого, в нашем конкретном случае, необходимо импортировать обобщенный тип FormEvent<T>
, которому перед размещением в аннотации единственного параметра слушателя события необходимо в качестве аргумента события указать тип нативного dom элемента HTMLFormElement
. Также стоит напомнить что в аннотации возвращаемого из слушателя события значения нет необходимости. Подобную рутинную работу необходимо делегировать выводу типов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Работа непосредственно с формой обусловила выбор более конкретного типа события, каковым в данном примере стал обобщенный тип FormEvent<T>
. При других условиях потребуются другие событийные типы. Кроме того, всегда можно сделать выбор в пользу базового для всех событийных типов SyntheticEvent<T>
ожидающего в качестве аргумента типа тип нативного dom элемента.
Мемоизация слушателей событий¶
Кроме этого, функциональным компонентам доступна мемоизация слушателей событий при помощи универсального хука useCallback<T>()
. Для этого понадобится импортировать универсальную функцию определяющую два обязательных параметра. В качестве первого параметра ожидается функция чье описание устанавливается в качестве аргумента функционального типа. Второй параметр принадлежит к типу массива, изменение элементов которого приводит к переинициализации функции переданной в качестве первого параметра. Поскольку в качестве аргумента функционального тпа ожидается тип описывающий первый параметр хука, то нет необходимости в аннотациях типа её параметров. Или в данном случае её единственного параметра представляющего объект события. В остальном, реализация ничем не отличается от предыдущего примера, поэтому повторяющийся код будет исключён.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
На этом рассмотрение типизирования функционального компонента определенного как Function Declaration, завершено. И поскольку тема получилась довольно не маленькая исключим затягивание и перейдем к рассмотрению следующего вида функциональных компонентов.
Определение компонента как Function Expression¶
Поскольку самое необходимое относящиеся ко всем видам React компонентов было рассмотрено в предыдущей теме, в этой и последующих, повествование будет сосредоточено исключительно на различиях.
Для определения функционального компонента как Function Expression декларация типов React предусматривает вспомогательный обобщенный тип FC<Props>
, чей идентификатор (имя) является сокращением от Function Component, а аргумент типа представляет пропсы и является необязательным. Поскольку вывод типов ориентируется на тип пропсов указанный или присущий по умолчанию в качестве аргумента типа, то в аннотировании первого параметра функционального компонента нет надобности. Помимо этого, тип пропсов, по умолчанию описывает необязательное поле children
принадлежащего к типу ReactNode
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Если тип пропсов указан в качестве аргумента типа FC<P>
и при этом не описывает поле children
, то оно всё равно будет определенно в объекте пропсов доступного в качестве первого параметра функционального компонента.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
В остальном все что было рассмотрено в предыдущей теме относительно пропсов и children
идентично и для данного способа типизирования функциональных компонентов.
При возникновении необходимости в определении второго параметра функционального компонента придется самостоятельно указывать аннотацию типа, поскольку по каким-то причинам обобщенный тип FC<P>
этого не предусматривает.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
В остальном все рассмотренное относительно рефов в теме посвященной функциональным компонентам определенным как Function Declaration, верно и для текущего вида определения.
При необходимости во втором параметре можно отказаться от типа FC<P>
в пользу ранее рассмотренного типа ForwardRefRenderFunction<T, P>
. При указании данного типа в аннотации функционального компонента, пропадает необходимость, как в явном аннотировании типов его параметров, так и в указании аргументов типа универсальной функции forwardRef<T, P>()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Важной особенностью использования обобщенного типа FC<P>
заключается в том, что он, помимо типа представляющего пропсы, также содержит описание типа возвращаемого функцией значения. Вроде бы так и должно быть, но нюанс заключается в том, что возвращаемое значение обязательно должно принадлежать к типу совместимому с ReactElement<P, T>
. Простыми словами на этапе компиляции возникнет ошибка если функциональный компонент, определенный как Fuction Expression, будет возвращать значение принадлежащие к типам number
, string
, boolean
или абсолютно любому массиву.
1 2 3 4 5 6 7 8 9 10 |
|
Поэтому в случае, предполагающем, что функциональный компонент, определенный как Function Expression, будет возвращать значение отличное от ReactElement<P, T>
, потребуется самостоятельно описать его сигнатуру. Что не представляет никакого труда.
1 2 3 4 5 6 7 8 |
|
Если в подобном определении функциональных компонентов существует частая потребность, будет целесообразней определить собственный тип подробно описывающий сигнатуру функции.
Для этого потребуется определить обобщенный тип с двумя необязательными параметрами. Первый необязательный параметр представляющий тип пропсов должен расширять и к тому же указывать в качестве типа по умолчанию тип object
. Второй необязательный параметр типа должен проделать тот же процесс только для нативного типа HTMLElement
.
Чтобы не заморачиваться в определении children
, указываем принадлежность первого параметра функции к уже знакомому обобщенному типу PropsWithChildren<P>
, которому в качестве аргумента типа устанавливаем первый параметр типа P
. Второму необязательному параметру функции указываем принадлежность к обобщенному типу MutableRefObject<E>
в качестве аргумента типа которому устанавливаем второй параметр типа E
. Осталось лишь указать принадлежность возвращаемого функцией значения к типу ReactNode
и тип CFC<P, E>
, что является сокращением от Custom Functional Component, готов сэкономить время и нервы разработчика.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|
На этом тема относящаяся функциональных компонентов себя полностью исчерпала, поэтому без лишних слов двигаемся к следующей теме посвященной классовым компонентам.