let's say I have function func
with 2 generic arguments
const func = <T extends {}, K extends keyof T>() => {};
and a type
interface Form {
a: boolean;
b: string;
}
then I can invoke them like so without any errors
func<Form, "a">();
func<Form, "b">();
Now I want func to accept only keys for which T[K] = string
In other words
func<Form, "a">(); // should pass
func<Form, "b">(); // should fail
My pseduo-typescript solution would be
const func = <T extends {}, K extends keyof T : where T[K] extends string>() => {};
but that of course doesn't go far. Is it even possible? Any help is appreciated.
CodePudding user response:
With a little helper type to get all the string types keys:
type StringKeys<T> = {
[K in keyof T]:
T[K] extends string ? K : never
}[keyof T]
type Test = StringKeys<{ a: boolean, b: string, c: string }>
// type: 'b' | 'c'
This utility type maps over all property of T
, and if the value type extends string the key name is preserved, and otherwise it is discarded as never.
Then you simply use that like:
interface Form {
a: boolean;
b: string;
}
const func = <T, K extends StringKeys<T>>() => {};
func<Form, "a">(); // error
func<Form, "b">(); // fine