2017-03-06 33 views
5

Ben yeni TS 2.1 Pick type amacını anlamış düşündü, ama sonra how it was being used in the React type definitions gördüm ve Anlamıyorum:Neden "T <T, K anahtarının T> türünü genişletiyor" yeni yanıtını "K" nin React'ın setState() `deki alt kümelerine izin veriyor?

interface PersonProps { 
    name: string; 
    age: number; 
} 

class Person extends Component<{}, PersonProps> { 
    test() { 
    this.setState({ age: 123 }); 
    } 
} 

Buradaki karışıklık: Bunu sağlayan

declare class Component<S> { 
    setState<K extends keyof S>(state: Pick<S, K>, callback?:() => any): void; 
    state: Readonly<S>; 
} 

Bu keyof S{ name, age } ancak 'u yalnızca age ile aradım - neden eksik name hakkında şikayet etmiyor?

İlk düşüncem, Pick bir dizin türü olduğundan, yalnızca tüm anahtarların bulunmasını gerektirmez. Mantıklı. Ben doğrudan türü atamak deneyin eğer:

const ageState: Pick<PersonProps, keyof PersonProps> = { age: 123 }; 

O anahtarı eksik name şikayetçi vermez: Ben bunu anlamıyorum

Type '{ age: number; }' is not assignable to type 'Pick<PersonProps, "name" | "age">'. 
    Property 'name' is missing in type '{ age: number; }'. 

. Bu tüm yaptığım S zaten atanmış olduğunu türüyle S doldurunuz oldu ve izin gitti görünüyor alt kümelerinde tüm tuşları gerektiren anahtarlarından. Bu büyük bir fark. Here it is in the Playground. Bu davranışı herkes açıklayabilir mi?

cevap

5

Kısa cevap: Eğer gerçekten açık bir türü isterseniz, sen Pick<PersonProps, "age"> kullanabilirsiniz, ancak bunun yerine daha kolay kullanım örtük türleri var.

Uzun cevap:

önemli nokta Kkeyof T uzanan bir genel tür değişken olmasıdır.

keyof PersonProps tipi "name" | "age" dize birleşimine eşittir. "age" tipi "name" | "age" türünü genişletmek için söylenebilir.

hatırlayın Pick tanımı: her K için araçlar

type Pick<T, K extends keyof T> = { 
    [P in K]: T[P]; 
} 

, bu tür tarafından tarif edilen nesnenin T mülkiyet K aynı tipte bir özelliği P olmalıdır.Sizin örnek oyun alanı kodu: genel tür değişkenleri Unwrapping

const person: Pick<PersonProps, keyof PersonProps> = { age: 123 }; 

, elde ederiz:

  • Pick<T, K extends keyof T>,
  • Pick<PersonProps, "name" | "age">
  • ,
  • [P in "name" | "age"]: PersonProps[P] ve nihayet
  • {name: string, age: number}.

Bu, elbette, { age: 123 } ile uyumsuzdur. Bunun yerine diyorsan:

const person: Pick<PersonProps, "age"> = { age: 123 }; 

sonra, aynı mantık şu, person tipi düzgün {age: number} eşit olacaktır.

Şüphesiz, TypeScript sizin için bu türlerin tümünü hesaplıyor - hatayı bu şekilde alıyorsunuz. Typescript zaten türlerini bilir yana {age: number} ve Pick<PersonProps, "age"> uyumludur, siz de tip impicit tutmak olabilir:

const person = { age: 123 }; 
+0

tipi ' "yaş"' türü ' "ad" uzatmak için söylenebilir * | "yaş". * Ah, bunu tahmin edemezdim, "isim" diye düşünürdüm | "yaş", "yaş" ı genişletir, başka şekilde değil. Açıklama için teşekkürler! – Aaron

+0

Bunu bir daha pişmanlık duyduğuma üzüldüm, ama şimdiki davranışı anladığımda (teşekkürler!), "Yaş" ın "yaş" türünün süper tipi olduğunu gerçekten rasyonelleştiremiyorum | "isim" ve bir alt türü değil, derleyicinin bunu nasıl gördüğünü açıkça gösterir. Görünüşte, eşdeğer arayüzlerin {name, age} ve '{age} 'birbirleriyle nasıl ilişkilendiğinin tersi görülüyor. Bu mantığı açıklayabilir misiniz? – Aaron

+1

Genel bir tür kısıtlamada, belki de "uzatmalar" ı "daha spesifik bir tür" olarak okumak en iyisidir. AB tipini düşünün = "a" | "b"; 've' tip ABC = "a" | "b" | "C"; '. 'Const abc: ABC =" c ";' 'değişkenine sahipseniz, bunu' AB' türünde bir değişkene atayamazsınız, ancak 'AB' türünde geçerli herhangi bir değer' ABC' için geçerli bir değerdir. "AB" nin daha spesifik bir "ABC" türü olduğu için, AB'nin * "ABC" yi uzatması söylenebilir. –