typescript - Varsayılan olarak bir sınıf içeren bir nesneyi dışa aktaran bir modül için ergonomik tipleri nasıl sağlayabilirim?
"Ergonomik" ile demek istediğim, "tüketicilerin
InstanceType<typeof mod["Foo"]>sözdizimini kullanmasını gerektirmemesi"
Bir JS kaynak dosyası için .d.ts yazıyorum. Birkaç ay içinde o JS dosyası TS'ye dönüştürülecek ama henüz dönüştüremiyoruz.
Dosya şöyle bir şey:
// module.js
class Foo {
sayFoo(){}
}
export default {
Foo
};
tsc bu şekilde bir .d.ts oluşturur:
// module.d.ts
declare class Foo {
sayFoo(): void;
}
declare const _default: {
Foo: typeof Foo;
};
export default _default;
Arayan kişinin sınıf türüne ulaşmak için gerçekten tuhaf engellerden geçmesi gerekiyor:
import mod from "./module"
function takesFoo(foo: InstanceType<typeof mod["Foo"]>) {
foo.sayFoo();
}
Ama eğer biraz tipler hakkında namespace kullanarak yalan söylersem:
export default NS;
// module.d.ts
declare namespace NS {
export class Foo {
sayFoo(): void
}
}
o zaman arayan kişi çok daha iyi bir tür düzeyinde API alır!
import mod from "./module";
function takesFoo(foo: mod.Foo) {
foo.sayFoo();
}
Sadece namespace kullanabilirdim, ama o zaman JS dosyasını TS'ye çevirdiğimizde sıkışırız. O noktada seçeneklerimiz şunlar olacak:
(A) Kütüphane giriş noktasını asla gerçek anlamda TS'ye dönüştürme. Kütüphanenin çoğunu TS ile yaz, sonra API'yi sarmalamak için bir .d.ts ile küçük bir JS dosyası kullan. Bu, gerçekten genel API'mize uyup uymadığımızı kontrol etmeyi kaldırır! Ve kafa karıştırıcı olurdu.
(B) Garip tür düzeyindeki API'yi çağıranlara zorla kabul ettirin. Belki bazı arayüzleri dışa aktararak darbeyi yumuşatabilir ve çağıranlara TS sınıf türlerinin bölünmüş kişiliğini öğretebilirsiniz.
TS'deki tür seviyesi noktaları hakkında bir seçeneği mi kaçırıyorum yoksa bir şeyi mi anlamıyorum?
Cevap #1
GÜNCELLEME: Düşündüğümden çok daha basit olabilir, ancak varsayılan ihracatları nasıl kullanacağınız konusundaki tavsiyem hala geçerli... Ayrıca bu aslında çalışmayabilir (daha fazla güncelleme: basit bir create-react-app ile oluşturulmuş bir ortamda denediğimde sorun gibi görünmüyor).
Mevcut varsayılan ihracınızla bu derleniyor gibi görünüyor:
import { Foo } from "./module"
const x = new Foo();
function f(y: Foo) {
y.sayFoo();
}
f(x);
Orijinal yanıt aşağıdadır:
class Foo { ifadesinin önüne export ekleme özgürlüğünüz var mı?
Böylece kullanıcılar şunları söyleyebilir:
import { Foo } from "./module";
ve sonra Foo'yu doğrudan kullanın:
function takesFoo(foo: Foo) {
Alternatif olarak, eğer Foo modülden dışa aktarılan tek şeyse ve onun varsayılan dışa aktarma olmasını istiyorsanız, onu bir nesneye sarmak yerine tek başına dışa aktarmak daha mantıklı olur:
export default Foo;
böylece kullanıcılar bunu içe aktarabilirdi:
import Foo from "./module";
default dışa aktarmayı düşündüğüm şekilde, yalnızca bir şey dışa aktaracak olursam en mantıklısı budur, bu durumda neden onu bir nesne içine sarmalayayım? Ve birden fazla şeyi dışa aktarmam gerekiyorsa, onları tek tek dışa aktarırım, böylece gerektiğinde { ... } ile içe aktarılabilirler.
