typescript - iki Pick yardımcı tip uygulaması arasındaki fark nedir
Bunu deniyorum: https://github.com/type-challenges/type-challenges/blob/master/questions/4-easy-pick/README.md
Aralarındaki farkı anlayamıyorum:
type MyPick<T, K> = T extends {} ? K extends keyof T ? {[P in K]: T[P]} : never : never
type MyPick<T extends {}, K extends keyof T> = {[P in K]: T[P]};
şuradan oynayabilirsiniz: bağlantı açıklamasını buraya girin
test durumu:
type A = {name: string; value: number;}
type B = MyPick1<A, 'name' | 'value'> // got {name: string} | {value: number}
type C = MyPick2<A, 'name' | 'value'> // got {name: string; value: number;}
Sonuçlarda kafam karışık, neden?
Cevap #1
İlk MyPick:
type MyPick<T, K> = T extends {} ? K extends keyof T ? {[P in K]: T[P]} : never : never
Herhangi iki genel türü kabul edebilir. Yani, bunu MyPick<1,2>/asla veya MyPick<[], false>/asla ile çağırabilirsiniz, bu elbette mantıklı değil ama yine de izin verilir çünkü kısıtlamalar yardımcı işlevin içinde kontrol edilir.
İkinci MyPick:
type MyPick<T extends {}, K extends keyof T> = {[P in K]: T[P]};
Bu MyPick her iki argüman için sınırlamalara sahiptir. İlk argüman pratikte any türü olan {}'den türemelidir ve ikinci argüman ilk argümanın bir anahtarı olmalıdır.
Örneğin:
type Test0 = MyPick1<2, 'toString'> // ok
type Test1 = MyPick1<2, 3> // expected error
Dikkat etmiş olabilirsiniz ki, hâlâ ilk argümanı ilkel bir tür olarak geçmenize izin veriliyor çünkü JS'deki her değer bir nesnedir, dolayısıyla kendi anahtarlarına sahiptir.
// "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"
type NumberKeys = keyof number;
Kullanıcının yalnızca bir nesneyi ilk argüman olarak geçmesine izin verilen bir kısıtlama uygulamak istediğinizi varsayıyorum, bu da Record<PropertyKey, any> kısıtlamasını kullanmanız gerektiği anlamına gelir. Örneğin:
type Test0 = MyPick1<{ age: number }, 'age'> // ok
type Test1 = MyPick1<2, 'toString'> // error
type Test2 = MyPick1<true, 3> // expected error
Neden MyPick1 bir Union türü döndürüyor?
Buna bak:
// Slightly reduced
type MyPick1<T, K> = K extends keyof T ? { [P in K]: T[P] } : never
type A = { name: string; value: number; }
type B = MyPick1<A, 'name' | 'value'> // got {name: string} | {value: number}
MyPick1 dağıtımsallık nedeniyle bir birleşim döndürür. Lütfen dokümanların bu bölümünü dikkatlice okuyun. Bu çok önemli bir özelliktir.
K birleşim türüne dağılıyorsa, bu, bu satırın { [P in K]: T[P] } her birleşime uygulandığı anlamına gelir.
Daha net olması için bir başka örneğe bakın:
type Distibutive<T> = T extends any ? T[] : never
type Result1 = Distibutive<'a' | 'b'> // "a"[] | "b"[]
// This is how you disable distributivity
type NonDistibutive<T> = [T] extends [any] ? T[] : never
type Result2 = NonDistibutive<'a' | 'b'> // ("a" | "b")[]
