Ответ
Для типизации данных из сторонних пакетов без TypeScript-типов можно использовать декларационные файлы (.d.ts).
- Если пакет не имеет типов, создай файл
types.d.tsв проекте:
declare module 'package-name' {
export function someFunction(arg: string): number;
export interface SomeInterface { /* ... */ }
}
- Для популярных пакетов часто есть готовые типы в
@types/package-name:
npm install --save-dev @types/package-name
- Можно расширить типы существующего модуля через
declare module:
declare module 'package-name' {
interface ExistingType {
newProperty: string;
}
}
- Для импорта JSON:
declare module '*.json' {
const value: Record<string, unknown>;
export default value;
} Ответ 18+ 🔞
Вот, смотри, как это работает на практике, а то некоторые думают, что TypeScript — это такая магия, которая сама всё про твой node_modules узнает. Не, блядь, не узнает.
Если ты взял какой-нибудь левый пакет с npm, который писал какой-то хипстер на коленке, и у него там типов нет — пиши пропало. Твой редактор начнёт орать красным, а компилятор материться, что не знает, что за хуйню ты импортируешь.
Вариант первый, для рукастых. Берёшь и сам описываешь, что этот пакет вообще из себя представляет. Создаёшь где-нибудь в проекте файлик, например, types.d.ts, и пишешь туда вот такую молитву:
// Объявляем модуль 'cool-but-typeless-package'
declare module 'cool-but-typeless-package' {
// Говорим TypeScript: "Поверь мне, там есть такая функция"
export function doAwesomeStuff(input: string): Promise<number>;
// А ещё там есть такой интерфейс, я видел
export interface AwesomeResult {
id: number;
status: 'ok' | 'fail';
data?: unknown;
}
}
Всё, теперь ты сам себе хозяин. TypeScript успокоится и будет думать, что так и было. Главное — не наврать в описании, а то в рантайме получишь undefined is not a function, и будешь потом ебаться с отладкой.
Вариант второй, для ленивых (и он часто срабатывает). Идешь и проверяешь, а нет ли для этого пакета готовых типов в репозитории @types. Это как библиотекарь, который уже за тебя всё прочитал и описал.
npm install --save-dev @types/cool-but-typeless-package
Если такой пакет есть — считай, тебе повезло, и можно не париться. Установил и забыл.
Вариант третий, для продвинутых: расширение существующих типов. Бывает, что типы в @types есть, но они кривые или неполные. Или ты сам добавил какую-то хуйню через Object.assign. Тогда можно аккуратно их дополнить, не ломая оригинал.
// В своём .d.ts файле
declare module 'already-typed-package' {
// Дополняем интерфейс, который уже объявлен в оригинальных типах
export interface ExistingConfig {
newOptionalField?: string; // Добавили своё поле
}
}
Ну и классика — импорт JSON-файлов. TypeScript по умолчанию их нихуя не понимает. Надо ему объяснить.
declare module '*.json' {
const value: Record<string, unknown>; // Или любой другой более конкретный тип
export default value;
}
Объяснил — и теперь можешь спокойно делать import data from './config.json' без всяких ошибок.
Короче, суть в чём: TypeScript — не телепат. Если типов нет, их надо либо найти, либо написать. Иначе вся эта затея с типами превращается в ебаное профанацию, и можно было сразу на чистом JS писать.