npm - TypeScript paketi yayınlarken isteğe bağlı eş bağımlılıklardan gelen türleri nasıl yönetirim?


Bir TypeScript paketini, girdi olarak bir peer bağımlılıktan ya da diğerinden birini kabul eden bir işlev sağlayacak şekilde npm'e yayınlarken, isteğe bağlı peer bağımlılıkları nasıl tanımlarım?

import { ExternalFoo } from 'foo';
import { ExternalBar } from 'bar';

export const customPackage = (source: ExternalFoo | ExternalBar) => {
    /* ... */
}

İki seçenekten biri eksik olduğunda, paketimi kullanan kişilerin hata almamasını nasıl önlerim?

Cevap #1

Typescript 3.8'den itibaren aşağıdaki sözdizimini kullanabilirsiniz:

import type { ExternalFoo } from "foo";

Yani eğer o kütüphaneyi sadece tür bilgisi için kullanıyorsanız, artık onu bir dependency veya optionalDependency olarak listelemeniz gerekmez. Onu bir peerDependency olarak bırakmayı tercih edebilirsiniz, böylece kullanıcılarınız bu bağımlılıklara sahip olduğunda, kütüphanenizle uyumlu sürümlerde olurlar. Doğal olarak, devDependency olarak eklemek de faydalıdır.

İthalat sadece oluşturulan d.ts dosyalarında var olacak, ancak .js dönüştürülmüş kodda olmayacak. Ama bir sorun var ki, eğer kullanıcıların o kütüphaneyi yüklemesi yoksa, o tip any olur ve bu kendi tiplerinizi biraz karıştırabilir. Örneğin, foo yüklü değilse, fonksiyonunuz şu hale gelir

customPackage = (source: any | ExternalBar) =>
// equivalent to customPackage = (source: any) =>

Ve bu özel tür açıklaması için, bar yüklü olsa bile, o tür denetiminde kullanılmayacağı için berbat bir durum. Yani artık o kütüphaneye bağımlı olmamanın bir yolu var, ama bu, o tür orada değilse bozulmayacak tür açıklamaları yazmanın zorluğunu çözmüyor.

Düzenleme: eksik türlerle nasıl başa çıkılacağıyla ilgili bu cevaba göz atın lütfen.

Referans

Cevap #2

Tüm mevcut cevapları birleştirerek, işte 2021 sonu itibariyle mevcut TypeScript sürümleri için bulduğum en iyi çözüm:

// @ts-ignore -- optional interface, will gracefully degrade to `any` if `foo` isn't installed
import type { Foo } from "foo";
import type { Bar } from "bar";

// Equates to `Bar` when `foo` isn't installed, `Foo | Bar` when it is
type Argument = any extends Foo ? Bar : (Foo | Bar);

export function customPackage(source: Argument): void {
  ...
}

Bunu kendiniz deneyebilirsiniz. Eğer foo yüklüyse, dışa aktarılan yöntem Foo veya Bar argümanlarını alacaktır ve eğer yüklü değilse, yalnızca Bar (hiçbir any değil) kabul edecektir.

İlgili makaleler