Расширение типов внешних библиотек в TypeScript

Расширение типов внешних библиотек в TypeScript

Задача: расширить 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, которые сам употребляю 🙂

Начать дискуссию