Задача: расширить typescript insterface npm пакета. Звучит просто.
Есть пакет store и он позволяет расширять свое API через плагины, и его тайпинги, которые ничего не знают про твои плагины и твой патчинг. В этих тайпингах есть тип StoreJsAPI и его нужно проапгрейдить, добавив некоторые параметры.
Исходный тип в сторонней библиотеке, я не имею возможности его редактировать.
interface StoreJsAPI {
get(key: string, optionalDefaultValue?: any): any;
set(key: string, value: any): any;
remove(key: string): void;
// остальные типы
}
Тип, который я хочу получить.
export type StoreMethodOptionsShared = {
whiteLabelKey?: string;
};
export type StoreGetOptions = StoreMethodOptionsShared & {};
export type StoreSetOptions = StoreMethodOptionsShared & {
expire?: number;
};
export type StoreRemoveOptions = StoreMethodOptionsShared & {};
interface StoreJsAPI {
get<T = any, R extends T = any>(key: string, optionalDefaultValue?: T, options?: StoreGetOptions): R;
set<T = any>(key: string, value: T, options?: StoreSetOptions): T;
remove(key: string, options?: StoreRemoveOptions): any;
}
Как можете заметить, появился аргумент `options`.
Можно загуглить и быстро найти решение, например такое
import 'store';
declare module 'store' {
interface StoreJsAPI {
// переопределяем все что нужно
}
}
Или вот такое
declare module 'store' {
import Store from 'store';
// мы не можем ипортировать StoreJsAPI, так как не экспортинтся
export interface StoreJsAPI extends (typeof Store) {
// переопределяем все что нужно
}
}
Но если вы попробуете это запустить, то ничего не будет работать. Как быть? Если вы внимательно посмотрите на файл типов, то увидите что-то такое:
interface StoreJsAPI {
//...
}
interface StoreJsEngine {
//...
}
interface StoreJsStorage {
//...
}
declare const store: StoreJsAPI;
declare module "store" {
export = store;
}
export = — это способ создания деклараций для модулей CommonJS, чтобы TypeScript мог корректно работать с их экспортами.
Внимательный пользователь увидит, что все интерфейсы находятся за пределами `declare module`, а это значит что эти интерфейсы доступны через `globalThis`, и это отлично, можно получить доступ к этим интерфейсам!
// store.d.ts
declare module 'store' {
export type StoreMethodOptionsShared = {
whiteLabelKey?: string;
};
export type StoreGetOptions = StoreMethodOptionsShared & {};
export type StoreSetOptions = StoreMethodOptionsShared & {
expire?: number;
};
export type StoreRemoveOptions = StoreMethodOptionsShared & {};
export interface StoreJsAPI extends globalThis.StoreJsAPI {
get<T = any, R extends T = any>(key: string, optionalDefaultValue?: T, options?: StoreGetOptions): R;
set<T = any>(key: string, value: T, options?: StoreSetOptions): T;
remove(key: string, options?: StoreRemoveOptions): any;
}
export const store: StoreJsAPI;
}
Мы используем globalThis.StoreJsAPI
что бы расширить его и делаем export const store: StoreJsAPI;
что бы задать новый тип.
И что бы это все заработало, не забудь, что tsconfig
должен включать (свойство include) этот файл store.d.ts
.
Вот такая небольшая записка разработчика, которая может кому-то помочь.
Заглядывайте в мой Telegram-канал @devdrafts_rss, где я делюсь материалами по IT, которые сам употребляю 🙂