I want to make the p1 property a required property when it passes typeGuard, but I have no idea how to define the red square box. Does anyone know?
typescript code is below
type T = {p1?: string; p2?:number; p3?: boolean}
const t: T = {p1: '1'};
function typeGuard<T extends object, Key extends keyof T>(t: T, key: Key): t is T & {[K in keyof T]: T[K]} {
return t[key] !== undefined;
}
if (typeGuard(t, 'p1')){
t.
}
You can trivially implement a generic, user-defined type guard function to verify the presence of a key in an object by using a few built-in type utilities:
The function looks like this:
function hasKey<K extends PropertyKey, T extends Partial<Record<K, any>>>(
obj: T,
key: K,
): obj is T & Required<Pick<T, K>> {
return key in obj;
}
Using it with the example data in your question looks like this:
type Example = {
p1?: string;
p2?: number;
p3?: boolean;
};
const example: Example = { p1: "1" };
if (hasKey(example, "p1")) {
example
//^? const example: Example & Required<Pick<Example, "p1">>
example.p1
//^? (property) p1: string
example.p2
//^? (property) p2?: number | undefined
example.p3
//^? (property) p3?: boolean | undefined
}
However, I'm not sure there's a great deal of value in such a function. The idiomatic inline expression — which uses the in
operator — is syntactically shorter and produces the same result:
See in the TS Handbook: The
in
operator narrowing
if ("p1" in example) {
example
//^? const example: Example & Required<Pick<Example, "p1">>
example.p1
//^? (property) p1: string
example.p2
//^? (property) p2?: number | undefined
example.p3
//^? (property) p3?: boolean | undefined
}
Note that things become a bit more complicated if undefined
is a union member for the optional value. Be sure to read about the compiler option noUncheckedIndexedAccess
to understand more. (The playground link above is configured with that option enabled.)