typescript - Benzer tür kısıtlaması ile koşullu tür arasındaki fark


Yerleşik yardımcı tür InstanceType için kendi uygulamamı yazdım:

type MyInstanceType<C extends abstract new (...args: any) => any>
  = C extends abstract new (...args: any) => infer R ? R : never

Aslında uygulandığı şekle çok yakındır:

type BuiltInInstanceType<C extends abstract new (...args: any) => any>
  = C extends abstract new (...args: any) => infer R ? R : any

tek fark ben son sözü never ile söylüyorum, oysa gerçek uygulamada orada any var

Bu, any'i ele alış biçiminde bir farkla sonuçlanır:

type MyWithAny = MyInstanceType<any> // unknown
type BuiltInWithAny = BuiltInInstanceType<any> // any

Bunun, koşullu tipin yanlış dalına bir şekilde ulaştığı anlamına geldiğini varsayıyorum

Yani soru şu, bu nasıl mümkün? Koşullu tipin, tip kısıtlaması ile aynı olduğunu ve bu yüzden koşullu tipe yanlış olan herhangi bir şeyin tip kısıtlamasına da yanlış olması gerektiğini ve böylece tip kısıtlaması hatasıyla sonuçlanması gerektiğini dikkate alırsak

Ve ikinci soru, neden MyWithAny tam olarak unknown ve örneğin never değil?

GÜNCELLEME: yanıt ve tartışmaya dayanarak, bu şekilde değerlendiriliyor (daha fazla ayrıntı için kabul edilen yanıta bakın):

  1. Genel işlevine any argümanı olarak MyWithAny ve BuiltInWithAny değerlendirilirken kullanılması, tür kısıtlamalarını tamamen devre dışı bırakmıştır. Bu yüzden MyInstanceType sanki
type MyInstanceType<C> = C extends abstract new (...args: any) => infer R ? R : never

ve BuiltInInstanceType tıpkı onun gibi değerlendirildi

type BuiltInInstanceType<C> = C extends abstract new (...args: any) => infer R ? R : any

bu, yanlış olan dalları mümkün kılar

  1. TS, bir koşullu tipin dalını değerlendiremediğinde, her iki dalın birleşim tipi olarak değerlendirir. Bu yüzden any, koşullu tipi karşılayabilecek veya karşılamayabilecek örnekleri içerdiğinden, MyWithAny tipinin R | never ve BuiltInWithAny tipinin R | any haline gelir.
  2. TS R'yi çözemediğinde, bunu unknown olarak değerlendirir. Bu yüzden, MyWithAny'in sonuç tipi unknown | never yani unknown olup, BuiltInWithAny'in sonuç tipi ise unknown | any yani any olur.

Cevap #1

Örneğiniz şöyle bir şeye indirgenebilir:

type WithNever = <T>(t: T) => T | never
type WithAny = <T>(t: T) => T | any

type NeverRetutn = ReturnType<WithNever>
type AnyRetutn = ReturnType<WithAny>

Biz T | never ve T | any ile ilgileniyoruz.

Eğer TypeScript T türünü çıkaramazsa, TS unknown türünü atayacaktır.

Örneğe bakın:

type ReturnUnknown = ReturnType< <T>(t: T) => T> // unknown

never nedir? (dokümanlar)

Never türü, her türün bir alt türüdür ve her türe atanabilir.

Aslında, never'i boş bir birleşim olarak ele almalısınız.

type Check = 1 | never // 1
type Check2 = unknown | never // unknown
type Check3 = any | never // any

Fark etmiş olabileceğiniz gibi, never her tipe atanmıştır.

Sorunuza geri dönelim. Aslında, siz türlerin birleşimini alıyorsunuz.

type MyWithAny = MyInstanceType<any> // R | never
type BuiltInWithAny = BuiltInInstanceType<any> // R | any

Umarım şimdi açıktır ki, R | never unknown olarak çözümlenecektir, çünkü R bilinmiyor ve never, unknown'a atanabilir.

R | any, unknown | any ile aynıdır ve herhangi bir tür any'ye atanabilir olduğundan, sadece any elde edersiniz.

Ama neden türlerin birleşimini alıyorsun? Koşullu tipin doğru veya yanlış dalını döndürmesi gerektiği açıktır, ama ikisini birden değil. TS’de işler böyle yürümüyor.

Çünkü bir argüman olarak any sağladınız, her dal uygulanır. Sanırım bu bekleniyor, çünkü sadece doğru dalın uygulanması veya sadece yanlış dalın uygulanması gerektiğini söyleyecek yeterli argümana sahip değilim.

Koşullu türün tür kısıtlamasıyla aynı olduğunu göz önünde bulundurursak, koşullu türe karşı yanlış olan herhangi bir şey tür kısıtlamasına karşı da yanlış olmalıdır ve bu nedenle bir tür kısıtlaması başarısız hatasıyla sonuçlanmalıdır

any türü aslında herhangi bir tür (her tür) olduğuna göre, neden false dalının uygulanması gerektiğini düşünüyorsunuz? Unutmayın, değerlerle değil, türlerle çalışıyorsunuz.

Falsy dalıyla ilgili beni şaşırtan şey, benim anladığım kadarıyla, oraya ne koyarsak koyalım her zaman never'a yönlendirilmesi gerektiğidir.

Her zaman yanlış dala değerlendirilemez. Böyle bir varsayım doğru değildir.

Şu sonraki örneği dikkate alın:

type CheckAny = any extends abstract new (...args: any) => any ? true : false

Yukarıdaki koşul true | false olarak değerlendirilir. Ve true | false birleşimi sadece yerleşik bir boolean tipidir.

Bence TypeScript yeterince zeki değil. TS sadece any tipinin constructor tipini genişletebileceğini söylüyor ama aynı zamanda bunu genişletemeyeceğini de.