Постепенно вводим TypeScript в ваш проект на React

Автор оригинала: Fernando Doglio
  • Перевод
Привет, Хабр!

В последнее время в области front-end особую популярность приобретает комбинация React+TypeScript. Соответственно, возрастает актуальность грамотной миграции с JavaScript на TypeScript, желательно в сжатые сроки. Сегодня мы хотели бы обсудить с вами именно эту тему.



Как безопасно собирать и вводить компоненты React TypeScript в ваш проект React JS.

Почему может потребоваться миграция с JS на TS? Причин на то может быть огромное множество, но суть не в этом. (Гипотетический) факт заключается в следующем: вам необходимо приступить к использованию TypeScript, и нужен легкий путь внедрения его в ваш проект. Мало того, все это нужно как-то сделать, не нарушив структуры всего имеющегося кода, и убедив команду в необходимости такого перехода.

Здесь будет продемонстрирован постепенный рефакторинг: как встраивать компоненты React в другую базу кода, а затем при помощи Bit безопасно вводить их в уже работающее приложение React на JavaScript.

Безопасное встраивание компонентов TS в проект на JS при помощи Bit




Существует множество способов перейти с React JS на React TS. Суть данной статьи – показать, как это делается поступательно. Аналогичный метод применим и в других случаях.
Базовая идея заключается в том, чтобы выжать максимум из компонентов React + при помощи Bit изолировать их друг от друга в собственной среде разработки Bit. В совокупности это позволяет собирать компоненты TS и безопасно вводить их в полнофункциональное приложение React JS.

Bit – это опенсорсный инструмент для извлечения компонентов из репозиториев Git. Bit позволяет собирать компоненты TS вне проекта, написанного на JS, выделяя под каждый автономную изолированную среду разработки, которая может работать и в других проектах, независимо от их конфигураций. Затем вы можете просто версионировать и «бит-импортировать» эти компоненты в ваш проект на JS, и они будут работать.

Наряду с Bit существует Bit.dev – удаленный хаб, в котором можно хранить эти компоненты, чтобы затем использовать повторно. Мы будем держать в Bit.dev компоненты TS, а оттуда станем вводить их в наш проект на React JS.



Пример: поиск разделяемых компонентов React в bit.dev

Пример использования


Для целей этой статьи разберем пример, который в мире фронтенда сравним с классическим “hello world”: речь пойдет о приложении для планирования дел.

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

Но я воспользуюсь вот этим приложением в качестве примера – можете с полным правом делать его форк или, как минимум, откройте ссылку и посмотрите весь его код.



github.com/deleteman/react-todo-demo

Данная база кода состоит из следующих компонентов:

TodoList: это главный компонент, отображаемый в форме поля для ввода текста с самой обычной кнопкой. Все находится в форме, после отправки которой текст добавляется в список, поддерживаемый основным приложением. Код этого компонента очень прост:

import React, { Component } from 'react'

class TodoList extends Component {
  render() {
    return (
      <div className="todoListMain">
        <div className="header">
          <form onSubmit={this.props.addItem}>
            <input placeholder="Task"
            ref={this.props.inputElement}
            value={this.props.currentItem.text}
            onChange={this.props.handleInput}
             />
            <button type="submit"> Add Task </button>
          </form>
        </div>
      </div>
    )
  }
}

export default TodoList

TodoItems: очень простой списковый компонент, используемый для вывода внутреннего списка элементов, добавленных через предыдущий компонент. Каждый из элементов кликабелен, и после нажатия на него он удаляется из списка. Код также весьма прост:

import React, { Component } from 'react'

class TodoItems extends Component {

  createTasks(item) {
    return <li key={item.key} onClick={() => this.props.deleteItem(item.key)}>{item.text}</li>
  }

  render() {
    const todoEntries = this.props.entries || []  
    const listItems = todoEntries.map(this.createTasks.bind(this))    

    return <ul className="theList">{listItems}</ul>
  }
}

export default TodoItems

В обоих случаях соответствующие методы принимаются как свойства (Props) из главного компонента App. Полный код этого компонента приведен здесь.

Согласен, это приложение очень простое, но, еще раз подчеркну, потенциально на его месте может быть любое приложение React, над которым вы работаете в настоящий момент – и внезапно получаете задачу приступить к миграции на TypeScript. Что же делать?

  • Вариант #1: Утерев слезы, начинаете переписывать всю базу исходного кода.
  • Вариант #2: Переименовываете все ваши файлы .js в .ts, настраиваете нужные шаги в сборочном процессе и умываете руки.
  • Вариант #3: Вы решаете, что действительно пора перейти к постепенной миграции всего старого кода, а весь новый код писать уже непосредственно на TypeScript.

Я хочу подробнее обсудить вариант #3, но, в принципе, не отказываю вам в том, что в одном и том же приложении у вас могут сосуществовать компоненты, написанные как на чистом JavaScript, так и на TypeScript.

Вводим TypeScript


Итак, в качестве примера предположим, что нам поручено добавить кнопку-переключатель (toggle) к каждому компоненту в нашем списке дел. После нажатия на элемент его необходимо переключить в фоновом режиме.

Ничего сверхъестественного, но, как вы помните, нас в данном случае интересует процесс, а не код как таковой.

Итак, мы не будем пытаться добавлять TypeScript в уже имеющийся у вас настроенный проект, чтобы случайно не сломать имеющуюся у вас сборку на несколько жней, а создадим совершенно новый проект, воспользовавшись чистым TypeScript:

$ npx create-react-app ts-components --template typescript

Обратите внимание: для использования npx нужна только новая версия NPM, и она включается в процесс установки в версии 5.2.0 и выше.

Точно как и ранее, в таком случае создается шаблон для проекта, но на этот раз в качестве базового языка мы используем TypeScript.

Плюс простой компонент-переключатель, пригодный для вставки в другой проект, не привнося при этом дополнительных зависимостей. Если вам интересно, как это делается, почитайте следующую статью о том, как писать компоненты для многократного использования.

import React, {useState} from 'react';

interface IActionProps {
	action: (status:boolean) => void,
	buttonText?: string
}

const Toggle = ({action, buttonText="Toggle"}: IActionProps) => {
	const [isSelected, setSelected] = useState(false)
	return (
		<button onClick={() => {
		setSelected(!isSelected)
		action(isSelected)
		}} >{buttonText}</button>
	)	
}

export default Toggle

Теперь, когда этот компонент написан, можно воспользоваться Bit (это опенсорсный инструмент для версионирования и публикации отдельных компонентов), чтобы извлечь данный конкретный компонент и поделиться им, чтобы впоследствии его можно было импортировать из нашего проекта, основанного на JavaScript.

// Устанавливаем Bit и инициализируем рабочее пространство в директории проекта 
$ yarn global add bit-bin
$ bit init --package-manager yarn// входим в систему (после того, как создадим аккаует и коллекцию в bit.dev)
$ bit login// добавляем все компоненты
$ bit add src/components/Toggle.tsx // конфигурируем компоненты (чтобы открепить компоненты от env)
$ bit import bit.envs/compilers/react-typescript --compiler// тегируем и экспортируем
$ bit tag –all

Так вы сконфигурируете ваш проект и настроите в нем новый компонент Toggle (переключатель) таким образом, чтобы его можно было разделять с другими проектами. Но, прежде, чем сможете сделать это на практике, вам необходимо залогиниться в Bit.dev (это хаб компонентов — сайт с реестром и документацией, дополняющий Bit в качестве площадки для публикации и предварительного просмотра компонентов).

Войдя в систему, просто создайте новую коллекцию под названием “toggler”, сделайте ее публичной, а затем в окне терминала выполните следующую команду:

$ bit export user-name.toggler

Если “user-name” – действительно ваше имя пользователя, то в результате будет экспортирован компонент, и вы сможете увидеть его на Bit.dev. Он должен будет выглядеть примерно так:



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

Например, здесь я обновил мой файл-образец, добавив пояснения о том, как использовать компонент Toggler (только не забудьте нажать кнопку “Save”, когда закончите!):



Теперь давайте рассмотрим, как импортировать этот новый компонент в ваше собственное React-приложение на основе JS.

Импорт внешнего компонента


Bit берет на себя компиляцию вашего кода TypeScript в JavaScript благодаря добавленному нами компилятору. Это решает все наши проблемы, и все, что нам осталось – добавить этот компонент в ваш проект в качестве зависимости.

Для всех целей я использовал здесь Yarn, но вы с тем же успехом могли бы воспользоваться NPM, все, что для этого нужно:

$ yarn add @bit/your-username.your-collection.your-component

В моем случае этот код превращается в:

$ yarn add @bit/deleteman.toggler.toggle

Обратите внимание: вы не сможете устанавливать компоненты, не войдя в систему (помните часть о $ bit login в этом руководстве?). Если вы хотели бы установить компоненты из реестра Bit, то нужно сконфигурировать реестр вручную, вот так:

$ npm config set '@bit:registry' https://node.bit.dev

Таким образом ваш компонент TypeScript (уже скомпилированный в JavaScript) включится в проект, и вы сможете ссылаться на этот компонент их вашего кода следующим образом:

import React, { Component, useState } from 'react'
import Toggle from '@bit/deleteman.toggler.toggle';


const TodoItem = ({text, itemKey}) => {

 	const [iClass, setIClass] = useState("white")

  	const toggleBackground = status => {
  		setIClass(status ? "white" : "black")
  	}

  	const toggleProps = {
  		action: toggleBackground,
  		buttonText: "Select"
  	}

    return <li className={iClass} key={itemKey} >{text}<Toggle {...toggleProps}/></li>
}

export default TodoItem

Обратите внимание на строку 2, где я импортирую внешний компонент, который собираюсь использовать в составе оператора возврата. Ничего сложного, не требуется вносить никаких дополнительных конфигурационных изменений ни в вашем проекте, ни где бы то ни было.
Поздравляю, теперь у вас есть рабочий проект, в котором используется как TypeScript, так и JavaScript, потенциально этого можно было сделать так, что вы бы этого даже не заметили!
Как я уже упоминал выше, полный код проекта выложен на GitHub!

Заключение


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

Уделите внимание Bit и посмотрите Bit.dev, найдите там другие компоненты, написанные одновременно на JavaScript и TypeScript, чтобы понять, как их пишут другие!
Издательский дом «Питер»
Компания

Комментарии 0

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

Самое читаемое