Как стать автором
Поиск
Написать публикацию
Обновить

Расширение типов внешних библиотек в 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, которые сам употребляю 🙂

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.