За обновлениями можно следить в telegram-канале https://t.me/quasiart

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 теперь подсказывает, какие пропсы можно передавать, а при сборке мы получим ошибку, если решим передавать пропсы неправильно. Удобно.