TL:DR
С 2020 по текущий 2023* занимаюсь проектом на React+TypeScript, в которой используется немного устаревшая UI-библиотека, написанная без TypeScript, и описаний типов для них нет.
Это печально, ведь приходится перепроверять по несколько раз, правильные ли пропсы передаются в компоненты. Во время сборки нет никакой гарантии, что в продакшн попадёт корректный код. Конечно, есть ручное тестирование, да и статическая типизация тоже не гарант. Но с типами всё-таки спокойнее.
К счастью, даже если библиотека написана без TypeScript, можно описать её типы. Описание типов в таком случае представляет собой отдельный файл с расширением d.ts, который можно хранить как в коде сторонней библиотеки, так и в своём проекте. Я выбрал последний вариант, так как это наиболее простой способ: не нужно проносить изменения в стороннюю библиотеку, проходя код ревью, публикацию новой версии и обновление версии в проекте.
Как используется библиотека
Библиотека устанавливается с помощью npm и поселяется в node_modules, версия фиксируется в package.json.
import { Input } from "@company/ui"
export const App = () => (
<form onSubmit="handleSubmit">
<Input.Text value="login" />
<Input.Password value="password" />
<Button isLoading={isLoading}>Войти</Button>
</>
)
Описание типов
Создаём файл company.ui.d.ts в каталоге types.
Название файла не принципиально, размещение тоже. Главное, чтобы путь до этих файлов был указан в tsconfig.json.
Содержимое файла company.ui.d.ts:
declare namespace CompanyUi {
interface InputPropsBase {
value?: string;
onChange?: (event: React.ChangeEvent) => void;
}
interface InputPasswordProps extends InputPropsBase {
refWrapper?: (input: HTMLInputElement) => void;
}
interface InputProps extends InputPropsBase {
type?: 'email' | 'tel' | 'text';
}
export class Input extends React.Component {
static readonly Password = class extends React.Component {
static theme: InputTheme;
};
}
// Utils
export const hello = (arg0: string) => void 0
}
declare module '@company/ui' {
export import Input = CompanyUi.Input;
export import hello = CompanyUi.hello;
}
Данный файл содержит описание компонента Input, а также его подкомпонента Password. Для наглядности добавил ещё описание утилиты, входящей в состав этой же библиотеки компонентов.
В рабочем проекте содержится описание более 10 компонентов, но все они описаны по тому же принципу.
Вывод
Библиотека описана, IDE теперь подсказывает, какие пропсы можно передавать, а при сборке мы получим ошибку, если решим передавать пропсы неправильно. Удобно.