В этом посте мы расскажем об использовании React с TypeScript. Если вам нужно быстро освежить в памяти TypeScript, я рекомендую вам прочитать мою предыдущую статью здесь.

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

Определение свойств компонента

type Props {
  name: string
  hometown: string
  favoriteRestaurant?: string
}
const ContactForm= ({ name, hometown, favoriteRestaurant }: Props) => (
  <>
    <p>
    Name: {name}
    Hometown: {hometown}. 
    {favoriteRestaurant ? 
     `favoriteRestaurant: ${favoriteRestaurant}`} : null }
    </p>
  </>
);

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

Normal declaration of default props 
const ContactForm= ({ name, hometown, favoriteRestaurant = ' Alidoro' }: Props)
React's alternative to default props 
ContactForm.defaultProps = {
  favoriteRestaurant: 'Alidoro'
};

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

React.FC
const ContactForm: React.FC<Props>  = ({ name, hometown, favoriteRestaurant }) => {
return (
  <>
  <p>
   Hello, {name}
   Hometown, {hometown}
   favoriteRestaurant, {favoriteRestaurant}
  </p>
  }
 </>
);

Что касается стрелочных функций, если мы хотим определить один тип варианта использования, мы можем воспользоваться преимуществами встроенного универсального типа React Function Component. Использование этого универсального типа позволяет нам просто передавать наши свойства параметру функции, не определяя наши собственные типы отдельно. У нас есть параметр props в угловых скобках, и мы передаем наши значения внутри параметров функции. Вы, вероятно, поймете, что таким же образом мы используем любой созданный нами общий тип.

Визуализация реквизита

type ContactForm {
  name: string
  hometown: string
}
type EventList= {
  contact: ContactForm
  greeting: string
  vip?: boolean
  renderVip?: (vip: greeting) => React.ReactNode;
}
const Greet = ({
  contact,
  greeting, 
  vip,
  renderVip
}: EventList) => (
  <>
    <p>
      Welcome, {contact.name} from {contact.hometown}
    </p>
    {vip ? (renderVip ? renderVip(greeting) : <p>{greeting}</p>)}
  <>
);
Passing the props:
<Greet
  contact={{ name: "Toby", hometown: NYC }},
  vip: true,
  greeting: "Thank you for you for your support" 
  renderVip={greeting => <h5> You are awesome!: {greeting}</h5>}
/>

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

Обработка состояния компонента

Inferred State on primitive values
const [name, setName] = React.useState('Toby'); //string
const [age, setAge] = React.useState(7); //number
Defining state
const [name, setName] = React.useState<string | null> (null);
const [age, setAge] = React.useState<number | null> (7);
type ContactForm {
  name: string
  age: number 
  favoriteRestaurant?: number
  }
const [form, setForm] = React.useState<ContactForm | null> (null); 

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

Обработчики событий

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) =>
  setQuery(event.currentTarget.value);

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

Есть еще кое-что, что нужно осветить, поскольку мы не рассмотрели создание с использованием типизированных ссылок, контекста или useReducer с состоянием компонента, но эти темы немного сложнее и потребуют демонстрационного приложения, чтобы они имели смысл. Я скоро расскажу о них в следующем сообщении в блоге! Надеюсь, это краткое введение помогло вам кое-что узнать об использовании реакции с TypeScript. Следите за следующей публикацией!