2017-03-06 2 views
5

私は新しいTS 2.1 Pick typeの目的を理解すると思ったが、その後、私はhow it was being used in the React type definitionsを見て、私は理解していない:なぜ新しい `Pick <T、K extends keyof T>型はReactの` setState() `の` K`の部分集合を許可しますか?

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

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

ここでの私の混乱がある:あなたがこれを行うことができます

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

そのkeyof S{ name, age }ですが、私はsetState()ageとしか電話しません - なぜそれが不足していると文句を言っていませんか?name

私の最初の考えは、Pickがインデックスタイプであるため、すべてのキーが存在する必要はありません。意味をなさないしかし、私は直接のタイプを割り当てようとします

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

それはが見つからないnameキー文句を言うん:

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

私はこれを理解していません。それは私がやったすべてがSが既にに割り当てられていることをタイプしてSに記入し、それがキーのをサブ設定可能からすべてキーを必要に行ってきましたようです。これは大きな違いです。 Here it is in the Playground。誰もこの行動を説明できますか?

答えて

5

短い回答:明示的なタイプが本当に必要な場合は、Pick<PersonProps, "age">を使用できますが、代わりに暗黙のタイプを使用する方が簡単です。

長い答え:

キーポイントはKkeyof Tを拡張し、汎用型変数であるということです。

タイプkeyof PersonPropsは、文字列ユニオン"name" | "age"と同じです。タイプ"age"はタイプ"name" | "age"を拡張すると言える。

リコールPickの定義がある:すべてのK手段

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

は、このタイプで記述されたオブジェクトは、TでプロパティKと同じタイプのプロパティPを有していなければなりません。あなたの例の遊び場コードは:ジェネリック型の変数をアンラップ

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

、我々が得る:

  • Pick<T, K extends keyof T>
  • Pick<PersonProps, "name" | "age">
  • [P in "name" | "age"]: PersonProps[P]、そして最終的に
  • {name: string, age: number}

これはもちろん、{ age: 123 }と互換性がありません。あなたの代わりに言うなら:

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

、その後、同じロジック以下、personのタイプが適切に{age: number}と同等になります。

もちろん、TypeScriptはこれらすべてのタイプを計算していますが、これはエラーの原因となります。活字体はすでにタイプを知っているので{age: number}Pick<PersonProps, "age">互換性があり、あなたにも型impicitを保つことがあります

const person = { age: 123 }; 
+0

タイプ '「年齢」は'タイプ '「名前」を拡張するために言うことができます* | "年齢"。* ああ、私はそれを推測していないでしょう、私は "名前" | 「年齢」は「年齢」を拡張します。説明ありがとう! – Aaron

+0

もう一度やってみると申し訳ありませんが、私は今行動を理解していますが(感謝!)、年齢のスーパータイプであることを本当に合理化することはできません。コンパイラがどのようにそれを見ているのかはっきりとしていますが、サブタイプではありません。一見等価なインターフェース '{name、age}'と '{age} 'がお互いにどう関係しているのかが逆になります。この根拠を説明できますか? – Aaron

+1

一般的なタイプの制約では、おそらく、 "より具体的なタイプ"であると解釈するのが最善です。タイプAB = "a" | "b"; 'とタイプABC =" a "| "b" | "c"; '。あなたが変数 'const abc:ABC =" c ";'を持っていれば、それを 'AB'型の変数に代入することはできませんでしたが、' AB'型の有効な値は 'ABC'の有効な値です。 「AB」はより特定のタイプの「ABC」であるため、「AB」は「ABC」を拡張すると言える。 –

関連する問題