Reputation: 547
Let's say I have the following interface and object:
interface Person {
name: string;
lastName?: string;
}
const obj: { [key: string]: Person } = {
a: { name: 'John' },
b: { name: 'Jane', lastName: 'Doe' },
}
This defines the type of the object such that its keys can be any string
. But I would like to still be able to infer the keys of the object (as it is static), which, in this case, I can't.
I can do something like this:
type ObjKeys = 'a' | 'b';
const obj: { [key in ObjKeys]: Person } //...
But it's verbose.
Is there a short way of saying "here is the type for all the values of this object but leave the keys as defined statically?"
Upvotes: 3
Views: 669
Reputation: 329773
You can't do this purely at the type level; if you annotate the type of obj
with {[k: string]: Person}
then the compiler will assume that this is the actual type to use and will not narrow it to something else based on the assignment of {a: {...}, b: {...}}
. Such control flow analysis only occurs for values whose type is a union, and {[k: string]: Person}
is not a union.
What I usually do in situations like this is to write a generic helper identity function from which the compiler can infer the type you're looking for:
const asPersonDict = <K extends PropertyKey>(
o: { [P in K]: Person }) => o;
And then you call the helper function instead of annotating the type:
const obj = asPersonDict({
a: { name: 'John' },
b: { name: 'Jane', lastName: 'Doe' },
});
/* const obj: {
a: Person;
b: Person;
} */
Upvotes: 2