Reputation: 633
How do I make a function accept only keys that map to certain type?
type Foo = {
// Arbitrary, can be any type
foo: number;
bar: number;
baz: string;
}
function f<T>(obj: T, key: keyof T) {
const foo = obj[key] // foo should be type number
}
const x: Foo = {foo: 0, bar: 1, baz: "a"}
f(x, "foo") // OK
f(x, "bar") // OK
f(x, "baz") // Should give error, because x["baz"] is not of type number
I have tried extending T, but can't get it to use the key from the argument:
function f<T extends {key: number}>(obj: T, key: keyof T) {} // Doesn't work
I have also tried extracting all fields from Foo which are numbers, and taking the keyof that, but Extract doesn't seem to work in quite that way:
function f<T>(obj: T, key: keyof (Extract<T, number>))) {} // Also doesn't work
Is this possible in TypeScript?
Upvotes: 2
Views: 73
Reputation: 2621
Interesting question! Managed to solve that puzzle. Yes, it can be done with the help of conditional types, but brace yourself, it's quite convoluted:
type NumberProp<T> = keyof T extends infer K
? K extends keyof T
? T[K] extends number
? K : never : never : never;
function f<T>(obj: T, key: NumberProp<T>) {
const foo = obj[key];
}
const x = {foo: 0, bar: 1, baz: "a"};
f(x, "foo"); // OK
f(x, "bar"); // OK
f(x, "baz"); // ERROR
Upvotes: 2