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

0 440

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

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

JavaScript const App = ({ title, score }: { title: string, score: number }) => ( <h1>{title} = {score}</h1> )

123 const App = ({ title, score }: { title: string, score: number }) => (  <h1>{title} = {score}</h1>)

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

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

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

React JS. Основы

Изучите основы ReactJS на практическом примере по созданию учебного веб-приложения

Получить курс сейчас!

JavaScript type Props = { title: string, score: number } const App = ({ title, score }: Props) => ( <h1>{title} = {score}</h1> )

12345678 type Props = {  title: string,  score: number} const App = ({ title, score }: Props) => (  <h1>{title} = {score}</h1>)

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

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

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

JavaScript type Props = { title?: string, score: number }

1234 type Props = {  title?: string,  score: number}

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

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

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

JavaScript type Props = { // primitive types title: string, score: number, isWinning: boolean }

123456 type Props = {  // primitive types  title: string,  score: number,  isWinning: boolean}

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

JavaScript type Props = { title: string[], // an array of string score: number, isWinning: boolean }

12345 type Props = {  title: string[], // an array of string  score: number,  isWinning: boolean}

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

JavaScript type Props = { priority: «high» | «normal» | «low», score: 5 | 9 | 10 }

1234 type Props = {  priority: «high» | «normal» | «low»,  score: 5 | 9 | 10}

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

JavaScript type Props = { user: { username: string, age: number, isMember: boolean } }

1234567 type Props = {  user: {    username: string,    age: number,    isMember: boolean  }}

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

JavaScript type Props = { user: { username: string, age: number, isMember: boolean }[] // right here }

1234567 type Props = {  user: {    username: string,    age: number,    isMember: boolean  }[] // right here}

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

JavaScript type Props = { // function that returns nothing onClick: () => void, // function accepts a parameter and has return type onChange: (target: string) => boolean, // function that takes an event handleSubmit: (event: React.FormEvent<HTMLFormElement>) => void }

12345678 type Props = {  // function that returns nothing  onClick: () => void,  // function accepts a parameter and has return type  onChange: (target: string) => boolean,  // function that takes an event  handleSubmit: (event: React.FormEvent<HTMLFormElement>) => void}

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

JavaScript const App = () => { const [message, setMessage] = useState(«») const onChange = (e: React.FormEvent<HTMLInputElement>): void => { setMessage(e.currentTarget.value); } // code omitted for clarity.. }

12345678910 const App = () => {  const [message, setMessage] = useState(«»)    const onChange = (e: React.FormEvent<HTMLInputElement>): void =>     {      setMessage(e.currentTarget.value);    }    // code omitted for clarity..}

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

JavaScript type Props = { children: React.ReactNode } const App = ({ children }: Props) => ( <div>{children}</div> )

1234567 type Props = {  children: React.ReactNode} const App = ({ children }: Props) => (  <div>{children}</div>)

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

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

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

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

JavaScript type Props = { title: string } const App: React.FC<Props> = ({title}) => { return ( <h1>{title}</h1> ) }

123456789 type Props = {  title: string} const App: React.FC<Props> = ({title}) => {  return (      <h1>{title}</h1>  )}

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

JavaScript type Props = { title: string } const App = ({ title }: Props) => <div>{title}</div> // App type will be inferred

123456 type Props = {  title: string} const App = ({ title }: Props) => <div>{title}</div>// App type will be inferred

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

JavaScript const App = ({ title }: { title: string }) => <div>{title}</div>

1 const App = ({ title }: { title: string }) => <div>{title}</div>

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

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

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

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

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

JavaScript const App = () => { const [title, setTitle] = useState(«») // type is string const changeTitle = () => { setTitle(9) // error: number not assignable to string! } }

1234567 const App = () => {  const [title, setTitle] = useState(«») // type is string   const changeTitle = () => {    setTitle(9) // error: number not assignable to string!  }}

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

JavaScript // title is string or null const [title, setTitle] = useState<string | null>(null) // score is number or undefined const [score, setScore] = useState<number | undefined>(undefined)

12345 // title is string or nullconst [title, setTitle] = useState<string | null>(null) // score is number or undefinedconst [score, setScore] = useState<number | undefined>(undefined)

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

JavaScript interface Member { username: string, age?: number } const [member, setMember] = useState<Member | null>(null)

123456 interface Member {  username: string,  age?: number} const [member, setMember] = useState<Member | null>(null)

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

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

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

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

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

JavaScript const AppContext = createContext({ authenticated: true, lang: ‘en’, theme: ‘dark’ }) const MyComponent = () => { const appContext = useContext(AppContext) //inferred as an object return <h1>The current app language is {appContext.lang}</h1> }

12345678910 const AppContext = createContext({   authenticated: true,  lang: ‘en’,  theme: ‘dark’}) const MyComponent = () => {  const appContext = useContext(AppContext) //inferred as an object  return <h1>The current app language is {appContext.lang}</h1>}

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

JavaScript { authenticated: boolean, lang: string, theme: string }

12345 {  authenticated: boolean,  lang: string,  theme: string}

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

JavaScript type Theme = ‘light’ | ‘dark’ const ThemeContext = createContext<Theme>(‘dark’)

12 type Theme = ‘light’ | ‘dark’const ThemeContext = createContext<Theme>(‘dark’)

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

JavaScript const App = () => { const theme = useContext(ThemeContext) return <div>The theme is {theme}</div> }

1234 const App = () => {  const theme = useContext(ThemeContext)  return <div>The theme is {theme}</div>}

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

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

JavaScript function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` points to the mounted text input element inputEl.current.focus(); }; return ( <> <input ref={inputEl} type=»text» /> <button onClick={onButtonClick}>Focus the input</button> </> ); }

12345678910111213 function TextInputWithFocusButton() {  const inputEl = useRef(null);  const onButtonClick = () => {    // `current` points to the mounted text input element    inputEl.current.focus();  };  return (    <>      <input ref={inputEl} type=»text» />      <button onClick={onButtonClick}>Focus the input</button>    </>  );}

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

JavaScript const inputRef = useRef<HTMLInputElement>(null)

1 const inputRef = useRef<HTMLInputElement>(null)

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

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

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

JavaScript const num = 24 // inferred as a number from the returned value below const result = useMemo(() => Math.pow(10, num), [num])

123 const num = 24// inferred as a number from the returned value belowconst result = useMemo(() => Math.pow(10, num), [num])

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

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

JavaScript const num = 9 const callbackFn = useCallback( (num: number) => { return num * 2 // type inferred as a number }, [num])

1234567 const num = 9 const callbackFn = useCallback(  (num: number) => {    return num * 2 // type inferred as a number  }, [num])

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

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

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

React JS. Основы

Изучите основы ReactJS на практическом примере по созданию учебного веб-приложения

Получить курс сейчас! JavaScript function useFriendStatus(friendID: number) { const [isOnline, setIsOnline] = useState(false); // code for changing the isOnline state omitted.. return isOnline; } const status = useFriendStatus(9) // inferred type boolean

12345 function useFriendStatus(friendID: number) {  const [isOnline, setIsOnline] = useState(false);  // code for changing the isOnline state omitted..  return isOnline;} const status = useFriendStatus(9) // inferred type boolean

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

JavaScript function useCustomHook() { return [«Hello», false] as const }

123 function useCustomHook() {  return [«Hello», false] as const }

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

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

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

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

JavaScript const App = () => ( <button onClick={ (e) => console.log(«Clicked»)}>button</button> // ^^^ e inferred as React.MouseEvent<HTMLButtonElement, MouseEvent> )

1234 const App = () => (  <button onClick={ (e) => console.log(«Clicked»)}>button</button>  // ^^^ e inferred as React.MouseEvent<HTMLButtonElement, MouseEvent>)

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

JavaScript const App = () => { const [email, setEmail] = useState(«»)const handleSubmit = (e: React.FormEvent) => { e.preventDefault() // handle submission here… alert(`email value: ${email}`) } return ( <form onSubmit={handleSubmit}> <div> <label> Email: <input type=»email» name=»email» onChange={(e) => setEmail(e.currentTarget.value)} // ^^^ onChange inferred as React.ChangeEvent /> </label> </div> <div> <input type=»Submit» value=»Submit» /> </div> </form> ) }

1234567891011121314151617181920212223242526 const App = () => {  const [email, setEmail] = useState(«»)const handleSubmit = (e: React.FormEvent) => {    e.preventDefault()    // handle submission here…    alert(`email value: ${email}`)  } return (    <form onSubmit={handleSubmit}>      <div>        <label>          Email:          <input            type=»email»            name=»email»            onChange={(e) => setEmail(e.currentTarget.value)}            // ^^^ onChange inferred as React.ChangeEvent          />        </label>      </div>      <div>        <input type=»Submit» value=»Submit» />      </div>    </form>  )}

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

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

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

JavaScript type Key = string | numberinterface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> { type: T; props: P; key: Key | null; }

12345 type Key = string | numberinterface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {    type: T;    props: P;    key: Key | null;}

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

JavaScript declare global { namespace JSX { interface Element extends React.ReactElement<any, any> { } } }

12345 declare global {  namespace JSX {    interface Element extends React.ReactElement<any, any> { }  }}

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

JavaScript type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

1 type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

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

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

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

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

JavaScript const App = ({ children }: { children: React.ReactNode }) => { return <div>{children}</div> } // At index.tsx <App> <Header/> <h2>Another title</h2> </App>

123456789 const App = ({ children }: { children: React.ReactNode }) => {  return <div>{children}</div>} // At index.tsx<App>  <Header/>  <h2>Another title</h2></App>

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

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

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

JavaScript const App = () : React.ReactElement | JSX.Element => { return <div>hello</div> }

123 const App = () : React.ReactElement | JSX.Element => {  return <div>hello</div>}

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

JavaScript interface FunctionComponent<P = {}> { (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null; propTypes?: WeakValidationMap<P> | undefined; contextTypes?: ValidationMap<any> | undefined; defaultProps?: Partial<P> | undefined; displayName?: string | undefined; }

1234567 interface FunctionComponent<P = {}> {  (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;  propTypes?: WeakValidationMap<P> | undefined;  contextTypes?: ValidationMap<any> | undefined;  defaultProps?: Partial<P> | undefined;  displayName?: string | undefined;}

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

JavaScript const App = () : JSX.Element | null => { return <div>hello</div> }

123 const App = () : JSX.Element | null => {  return <div>hello</div>}

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

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

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

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

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

JavaScript type ButtonProps = { children: React.ReactNode onClick: () => void } const Button = ({ children, onClick }: ButtonProps) => { return <button onClick={onClick}>{children}</button> }

12345678 type ButtonProps = {  children: React.ReactNode  onClick: () => void} const Button = ({ children, onClick }: ButtonProps) => {  return <button onClick={onClick}>{children}</button>}

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

JavaScript type ButtonProps = { children: React.ReactNode onClick: () => void disabled: boolean type: ‘button’ | ‘submit’ | ‘reset’ | undefined }

123456 type ButtonProps = {  children: React.ReactNode  onClick: () => void  disabled: boolean  type: ‘button’ | ‘submit’ | ‘reset’ | undefined }

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

JavaScript type ButtonProps = React.ComponentPropsWithoutRef<«button»> const Button = ({ children, onClick, type }: ButtonProps) => { return ( <button onClick={onClick} type={type}> {children} </button> ) }

123456789 type ButtonProps = React.ComponentPropsWithoutRef<«button»> const Button = ({ children, onClick, type }: ButtonProps) => {  return (    <button onClick={onClick} type={type}>      {children}    </button>  )}

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

JavaScript type ImgProps = React.ComponentPropsWithoutRef<«img»> const Img = ({ src, loading }: ImgProps) => { return <img src={src} loading={loading} /> }

12345 type ImgProps = React.ComponentPropsWithoutRef<«img»> const Img = ({ src, loading }: ImgProps) => {  return <img src={src} loading={loading} />}

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

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

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

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

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

JavaScript interface ImgProps extends React.ComponentPropsWithoutRef<«img»> { customProp: string; } const Img = ({ src, loading, customProp }: ImgProps) => { // use the customProp here.. return <img src={src} loading={loading} />; }

12345678 interface ImgProps extends React.ComponentPropsWithoutRef<«img»> {  customProp: string;} const Img = ({ src, loading, customProp }: ImgProps) => {  // use the customProp here..  return <img src={src} loading={loading} />;}

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

JavaScript interface headerProps extends React.ComponentPropsWithoutRef<«h1»> { variant: «primary» | «secondary»; } const Header = ({ children, variant }: headerProps) => { return ( <h1 style={{color: variant === «primary» ? «black» : «red» }}> {children} </h1> ); };

1234567891011 interface headerProps extends React.ComponentPropsWithoutRef<«h1»> {  variant: «primary» | «secondary»;} const Header = ({ children, variant }: headerProps) => {  return (    <h1 style={{color: variant === «primary» ? «black» : «red» }}>      {children}    </h1>  );};

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

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

ComponentPropsWithoutRef против [Element] HTMLAttributes

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

JavaScript type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> type ImgProps = React.ImgHTMLAttributes<HTMLImageElement>

123 type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> type ImgProps = React.ImgHTMLAttributes<HTMLImageElement>

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

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

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

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

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

JavaScript interface HtmlAttributes { disabled: boolean } interface ButtonHtmlAttributes extends HtmlAttributes { type: ‘Submit’ | ‘Button’ | null }

1234567 interface HtmlAttributes {  disabled: boolean} interface ButtonHtmlAttributes extends HtmlAttributes {  type: ‘Submit’ | ‘Button’ | null}

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

JavaScript type HtmlAttributes = { disabled: boolean } type ButtonHtmlAttributes = HtmlAttributes & { type: ‘Submit’ | ‘Button’ | null }

1234567 type HtmlAttributes = {  disabled: boolean} type ButtonHtmlAttributes = HtmlAttributes & {  type: ‘Submit’ | ‘Button’ | null}

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

JavaScript type isLoading = boolean type Theme = «dark» | «light» type Lang = «en» | «fr»

123 type isLoading = booleantype Theme = «dark» | «light»type Lang = «en» | «fr»

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

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

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

Автор: Nathan Sebhastian

Источник: webformyself.com

Оставьте ответ

Ваш электронный адрес не будет опубликован.