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
