This is a basic implementation of Typescript's Pick
utility type from this tuturial
type ObjectWithKeys<T, K extends keyof T> = {
[P in K]: T[P];
};
I undestand what it does, but I find the use of K extends keyof T
a bit confusing. We want to ensure that K is a member (or union of members) of the union type keyof T
. It's never going to "extend" it, so why use the extends
operator here?
Is Typescript lacking an operator and this is the best current option?
CodePudding user response:
I've often been bothered by that reuse of extends
too, but it's true in a way. The type is "a" | "b" | "c"
, but you could use something else assignable to that, such as "a" | "b"
:
type ObjectWithKeys<T, K extends keyof T> = {
[P in K]: T[P];
};
type A = {
a: number;
b: number;
c: number;
}
type X = ObjectWithKeys<A, "a" | "b">; // Works
In that sense, you can see "a" | "b"
as a subtype (more specialized version) of "a" | "b" | "c"
, just like an object type with more properties is a subtype of one with a subset its its properties (which we also represent via extends
, with interfaces and class
syntax).
We're (well, okay, I'm) used to thinking of subtypes as having "more stuff" than supertypes because I'm used to thinking about object types (where it's true, {a: number; b: number;}
is a subtype of {a: number;}
), but with unions it's the other way around, subtypes have fewer members than supertypes.