typescript - Genel yöntem argümanının geçirilen tüm birleşim olması için zorla
Bir yöntemi, genel bir parametre ile birleşim türüne zorlamaya çalışmak. Sorun şu ki, TS bu yöntemin uygulanmasının sadece birleşimi tatmin etmesiyle yetinmesine izin veriyor, birleşimin kendisi olması gerekmez. Burada 'tatmin etme' terimini yanlış kullandığımı düşünebilirim, ama umarım noktam aşağıdaki örnekte net bir şekilde ortaya çıkıyordur.
interface IFoo<TArg> {
myMethod(arg: TArg): void;
}
class Foo implements IFoo<string | number> {
// TS doesn't complain because string satisfies string | number.
// How can I make TypeScript force arg to explicitly be string | number?
myMethod(arg: string): void {
//
}
}
class Foo2 implements IFoo<string | number> {
// What I want TS to enforce:
myMethod(arg: string | number): void {
//
}
}
Tuple'larla uğraştım ve bunu çözebilecek bir yardımcı tür aramaya çalıştım ama nafile.
düzenle: Oyun alanı bağlantısı: https://tsplay.dev/wOx5EN
Cevap #1
TypeScript'te yöntem parametrelerinin iki değerli (bivariant) olması gerçeği ile karşı karşıyasınız. Bu, bir arabirimi uygularken bir yöntem parametresinin türünü daraltmanıza izin verildiği anlamına gelir; örneğin string | number türünü yalnızca string olarak daraltmak gibi. Bu tür güvenli değil (ya biri myMethod() çağrısını bir sayı argümanı ile yaparsa?), ancak bazı önemli kullanım durumları için uygundur (nedenini anlamak için bu SSS girdisine de bakabilirsiniz).
Şimdi, bu durum önceden tüm fonksiyonlar için geçerliydi, ancak --strictFunctionTypes derleyici bayrağı tanıtıldığından beri, iki yönlülük kontrolünü sadece metotlarla sınırlayabilir ve diğer fonksiyon türlerinin parametreleri güvenli karşıt varyant şekilde kontrol edilir. (Daha fazla bilgi için TypeScript'te Varyans, Eşvaryans, Karşıt Varyans ve İki Yönlülük Arasındaki Farklar konusuna bakabilirsiniz.)
Bu, sorunu atlatmanın bir yolu, IFoo<TArg> içinde myMethod()'i bir yöntem türü yerine bir fonksiyon türü ile bir özellik olarak tanımlamaktır:
interface IFoo<TArg> {
myMethod: (arg: TArg) => void;
}
Bu durum, uygulayan sınıfların myMethod yöntemini bir metod yerine örnek özelliği yapmaya zorlayacak gibi görünebilir, ama durum böyle değil. Yani bu gayet iyi çalışır:
class Foo2 implements IFoo<string | number> {
myMethod(arg: string | number): void { // okay
//
}
}
Ama bunu bir yöntem olarak uygulasanız bile, parametre artık arayüz fonksiyon özelliği parametresine karşı kontravaryant olarak kontrol edilir:
class Foo implements IFoo<string | number> {
myMethod(arg: string): void { // error!!!
//
}
}
ve aradığınız hatayı alıyorsunuz.
Koda yönelik oyun alanı bağlantısı
