Как импортировать класс в файл объявления типов (.d.ts) в TypeScript?
Решение: используйте import type или глобальное объявление
Проблема в том, что файлы .d.ts имеют строгие правила: если вы используете import или export в корне файла, он становится модулем. В модуле все типы и значения локальны, и чтобы ссылаться на типы из другого файла, нужно их явно импортировать. Но обычный import (даже с типом) может конфликтовать, если вы не хотите делать файл модулем.
Вот два основных рабочих подхода:
1. Используйте import type (рекомендуется для модулей)
Если ваш файл .d.ts уже содержит export или import (то есть он модульный), то используйте import type. Это правильный способ импортировать только типы, без рантайм-значений. Пример:
// my-library.d.ts
export class User {
name: string;
constructor(name: string);
greet(): string;
}
export function createUser(name: string): User;
// extra-types.d.ts
import type { User } from './my-library';
export function getUserInfo(user: User): string;
Обратите внимание: import type стирается при компиляции — в JavaScript его не будет. Это идеально для файлов объявлений.
2. Используйте глобальные типы (без импорта/экспорта)
Если вы не хотите делать файл модулем (то есть все объявления должны быть глобально доступны без импорта), объявите типы глобально. Для этого:
- В файле
my-library.d.tsне используйтеexport— просто объявите класс на уровне модуля. - В файле
extra-types.d.tsпросто используйтеUserнапрямую.
// my-library.d.ts
declare class User {
name: string;
constructor(name: string);
greet(): string;
}
declare function createUser(name: string): User;
// extra-types.d.ts
// Не нужно импортировать — User доступен глобально
declare function getUserInfo(user: User): string;
Но будьте осторожны: глобальные типы могут конфликтовать с другими библиотеками. Лучше использовать модульный подход.
3. Используйте extends или interface (альтернатива)
Если вам нужно только описать структуру, а не сам класс, можно объявить интерфейс в одном файле и импортировать его:
// my-library.d.ts
export interface IUser {
name: string;
greet(): string;
}
export class User implements IUser {
name: string;
constructor(name: string);
greet(): string;
}
// extra-types.d.ts
import type { IUser } from './my-library';
export function getUserInfo(user: IUser): string;
Почему import { User } не работает?
Потому что User в .d.ts — это класс (значение и тип одновременно). Если вы пишете import { User }, TypeScript ожидает, что это рантайм-импорт, но в .d.ts это запрещено. import type решает эту проблему, сообщая компилятору: «мне нужен только тип, не генерируй код».
Итог: если ваш файл .d.ts — модуль (содержит export), используйте import type. Если это глобальный файл — просто объявляйте без export.
Дополнительный подход: объединение в один файл
Если у вас небольшой проект, проще всего объединить все объявления в один файл .d.ts. Это избавит от проблем с импортами полностью. Например:
// types.d.ts
declare class User {
name: string;
constructor(name: string);
greet(): string;
}
declare function createUser(name: string): User;
declare function getUserInfo(user: User): string;
Такой файл будет глобальным, и все типы доступны без импорта. Недостаток — файл может стать слишком большим, но для небольших библиотек это отличное решение.
Используйте declare module
Если вы типизируете внешнюю библиотеку (например, из npm), можно использовать declare module с относительным импортом:
// extra-types.d.ts
declare module 'my-library' {
export class User {
name: string;
constructor(name: string);
greet(): string;
}
}
// Теперь можно импортировать User из 'my-library' в других .d.ts файлах
import { User } from 'my-library';
Этот подход часто используется в DefinitelyTyped (@types/*). Он позволяет переопределить или расширить типы для существующей библиотеки.
Выберите способ, который лучше подходит под архитектуру вашего проекта. Для простых случаев — глобальный файл, для сложных — import type или declare module.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги