When the constraint
T extends { [key in keyof Partial<GM>]: 1 }
is applied, it means that T
must be able to be assigned to {a?:1, b?:1, c?:1}
. This not only includes types you intend to support, like {a: 1}
, but also types you may not have intended to support. In TypeScript, object types are considered "extendable" or "open", meaning properties can be added to them. Therefore, a type like
{a?: 1, b?:1, c?:1, oops: string}
is also supported:
const oopsie = getVF({ a: 1, oops: "oops" }) // no error!
// const oopsie: VMeth<GM, Pick<GM, "a" | "oops">
This leads to the compiler rightly complaining about the following:
// Type 'keyof T' does not satisfy the constraint 'keyof GM'.
If you want to specifically limit the keys of part
to those of GM
, you can make your function generic in those keys using K
:
const getVF = <K extends keyof GM>(part: Record<K, 1>):
VMeth<GM, Pick<GM, K>> => {
return function () { } as any
}
Now, K
must be a subset of
"a" | "b" | "c"
and cannot include
"oops"
or any other unauthorized key. The functionality remains the same for your desired use case:
fd({ a: 1, b: "", c: "s" }, { a: 1 });
// const fd: (old: GM, n: Pick<GM, "a">) => any
You will now receive compiler warnings if an unexpected property is added:
getVF({ a: 1, oops: "oops" }); // error, excess property!
Even though it's still possible to sneak in an excess property by being tricky:
const existingObj = {a: 1, oops: "oops"} as const;
const aliased: {a: 1} = existingObj;
const okay = getVF(aliased); // no error
// const okay: VMeth<GM, Pick<GM, "a">>
At least the resulting value is always Pick<GM, "a">
and not an invalid selection like
Pick<GM, "a" | "oops">
.
Click here to access the code on the TypeScript Playground