I thought I understood the purpose of the new TS 2.1 Pick
type, but then I saw how it was being used in the React type definitions and I don't understand:
declare class Component<S> {
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
state: Readonly<S>;
}
Which allows you to do this:
interface PersonProps {
name: string;
age: number;
}
class Person extends Component<{}, PersonProps> {
test() {
this.setState({ age: 123 });
}
}
My confusion here is that keyof S
is { name, age }
but I call setState()
with only age
-- why doesn't it complain about the missing name
?
My first thought is that because Pick
is an index type, it simply doesn't require all the keys to exist. Makes sense. But if I try to assign the type directly:
const ageState: Pick<PersonProps, keyof PersonProps> = { age: 123 };
It does complain about the missing name
key:
Type '{ age: number; }' is not assignable to type 'Pick<PersonProps, "name" | "age">'.
Property 'name' is missing in type '{ age: number; }'.
I don't understand this. It seems all I did was fill in S
with the type that S
is already assigned to, and it went from allowing a sub-set of keys to requiring all keys. This is a big difference. Here it is in the Playground. Can anyone explain this behavior?
"age"
can be said to extend the type"name" | "age"
. Ah, I wouldn't have guessed that, I would think that"name" | "age"
extends"age"
, not the other way. Thanks for the explanation! – Sonorant