type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
I know mapped type { [P in keyof T]: T[P] }
and keyof
, but how do they work together and filter never
?
type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
I know mapped type { [P in keyof T]: T[P] }
and keyof
, but how do they work together and filter never
?
If never is present in a union, it is removed from the union. So never | "A"
will just be "A"
.
Given this behavior, we want to construct a mapped type that has never
as the type for the keys we don't want in the result, and the name of the key as the type of the key for the keys we want in the result. We do this using the conditional type T[K] extends Function ? K : never
on each property. So for example:
type FunctionPropertyNamesMapped<T> = { [K in keyof T]: T[K] extends Function ? K : never }
type Test = FunctionPropertyNamesMapped<{
a: number,
fn: () => {}
}>
// Test is the same as
// {
// a: never;
// fn: "fn";
//}
Given this new mapped type, if we get a union of all key types in it (using [keyof T]
) we would get the union never | "fn"
which reduces to just "fn"
You can also listen to my audio explanation of something similar here