2017-03-06 5 views
5

Ich dachte, ich den Zweck des neuen TS 2.1 Pick type verstanden, aber dann sah ich how it was being used in the React type definitions und ich verstehe nicht:Warum erlaubt das neue `Pick <T, K extends keyof T>` -Typ Subsets von `K` in Reacts` setState() `?

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

Welche Sie dies tun können:

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

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

Meine Verwirrung ist hier dass keyof S ist { name, age }, aber ich rufe setState() mit nur age - warum beschwert es sich nicht über die fehlende name?

Mein erster Gedanke ist, dass, weil Pick ein Indextyp ist, es einfach nicht alle Schlüssel benötigt, um zu existieren. Macht Sinn. Aber wenn ich versuche, direkt den Typ zuzuordnen:

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

Es hat beschweren sich über die fehlende name Schlüssel:

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

ich das nicht verstehen. Es scheint alles, was ich war in S mit dem Typ füllen haben, dass S bereits zugeordnet ist, und es ging von so dass ein Untersatz der Schlüssel zu erfordern alle Tasten. Das ist ein großer Unterschied. Here it is in the Playground. Kann jemand dieses Verhalten erklären?

Antwort

5

Kurze Antwort: Wenn Sie wirklich einen expliziten Typ möchten, können Sie Pick<PersonProps, "age"> verwenden, aber es ist einfacher, stattdessen implizite Typen zu verwenden.

Lange Antwort:

Der entscheidende Punkt ist, dass die K eine Variable generische Typ ist, der keyof T erstreckt.

Der Typ keyof PersonProps entspricht der Zeichenfolgenvereinigung "name" | "age". Der Typ "age" kann den Typ "name" | "age" erweitern.

Recall die Definition von Pick ist:

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

die für jeden K bedeutet, das Objekt von diesem Typ beschrieben, eine Eigenschaft haben muß P gleichen Typ wie die Eigenschaft K in T.Ihr Beispiel Spielplatz Code war:

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

Auswickeln des generischen Typ Variablen, erhalten wir:

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

Dies ist natürlich inkompatibel mit { age: 123 }. Wenn Sie stattdessen sagen:

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

dann, nach der gleichen Logik, wird die Art der person richtig äquivalent zu {age: number}.

Natürlich berechnet TypeScript alle diese Typen für Sie trotzdem - so haben Sie den Fehler bekommen. Da Typoskript bereits die Typen kennt {age: number} und Pick<PersonProps, "age"> kompatibel sind, könnten Sie auch halten den Typ impicit:

const person = { age: 123 }; 
+0

* Die Art '„Alter“' kann gesagt werden, den Typ '„name“erweitern | "age" '. * Ah, das hätte ich nicht gedacht, ich würde das" name "| denken "Alter" "verlängert" "Alter", nicht umgekehrt. Danke für die Erklärung! – Aaron

+0

Entschuldigen Sie, dass ich das noch einmal anprangere, aber während ich das Verhalten jetzt verstehe (danke!), Kann ich nicht wirklich rationalisieren, wie "Alter" ein Super-Typ von "Alter" ist "name" 'und kein Untertyp, obwohl es klar ist, wie der Compiler es sieht. Es scheint, dass die umgekehrte Beziehung zwischen den scheinbar äquivalenten Schnittstellen '{name, age}' und 'age} besteht. Kannst du diese Logik erklären? – Aaron

+1

In einem generischen Typ Einschränkung, ist es vielleicht am besten zu lesen "erweitert" als "ist ein spezifischer Typ von." Betrachte 'type AB =" a "| "b"; "und" type ABC = "a" | "b" | "c"; ". Wenn Sie eine Variable 'const abc: ABC = "c"; 'haben, können Sie dies nicht einer Variablen vom Typ' AB 'zuweisen, aber jeder gültige Wert vom Typ' AB 'ist ein gültiger Wert von' ABC '. Da "AB" eine spezifischere Art von "ABC" ist, kann "AB" als * extend * "ABC" bezeichnet werden. –

Verwandte Themen