Reputation: 54821
Is it possible to create a function that uses keyof
to access a property of an object, and have TypeScript infer the return value?
interface Example {
name: string;
handles: number;
}
function get(n: keyof Example) {
const x: Example = {name: 'House', handles: 8};
return x[n];
}
function put(value: string) {
}
put(get("name"));
// ^^^ Error: Argument of type 'string | number' is not assignable to parameter of type 'string'
TypeScript is merging all the allowed types together, but when the function is called with the value "name"
it does not infer the type is string
.
I can resolve the issue by casting the type.
put(get("name") as string);
Is there a way to do this without casting?
Upvotes: 4
Views: 3237
Reputation: 330316
Sure, you just have to make get
generic so that it doesn't return the union of all possible output types:
function get<K extends keyof Example>(n: K) {
const x: Example = { name: "House", handles: 8 };
return x[n];
}
Now the signature is inferred to be:
// function get<K extends "name" | "handles">(n: K): Example[K]
Where the return type, Example[K]
, is a lookup type representing the type you get when you index into an Example
with key K
.
When you call it, K
is inferred to be a string literal type if it can be:
get("name"); // function get<"name">(n: "name"): string
And Example["name"]
is equivalent to string
. So now your call works as desired:
put(get("name")); // okay
Hope that helps. Good luck!
Upvotes: 12