Reputation: 430921
The TypeScript documentation on enums says:
enum members also become types as well!
I would like to have a function that takes a generic value that is an enum member and uses the specific enum member's type.
I see that I can use the enum member as a type:
enum Kind {
Apple,
Banana,
}
type Example1 = Kind.Apple;
I can use the enum member in a generic type context:
interface Wrapper<K> {
kind: K;
}
type Example2 = Wrapper<Kind.Apple>;
When I pass the enum member to a function, it loses the fact that it's a specific enum member and instead makes it the parent's enum type:
const returned = <K>(kind: K): Wrapper<K> => ({
kind,
})
const theValue = returned(Kind.Apple);
// Type 'Kind' is not assignable to type 'Kind.Apple'.
const butNot: Example2 = theValue;
Upvotes: 2
Views: 1742
Reputation: 430921
You can explicitly specify what the generic type should be on the call to returned
:
enum Kind {
Apple,
Banana,
}
interface Wrapper<K> {
kind: K;
}
const returned = <K>(kind: K): Wrapper<K> => ({
kind,
})
const theValue = returned<Kind.Apple>(Kind.Apple);
const thisWorksNow: Wrapper<Kind.Apple> = theValue;
Upvotes: 0
Reputation: 51629
The reason why kind
parameter type is widened from Kind.Apple
to Kind
is spelled out in https://github.com/Microsoft/TypeScript/pull/10676 :
During type argument inference for a call expression the type inferred for a type parameter T is widened to its widened literal type if:
- all inferences for T were made to top-level occurrences of T within the particular parameter type, and
- T has no constraint or its constraint does not include primitive or literal types, and
- T was fixed during inference or T does not occur at top-level in the return type.
If, as mentioned in the second bullet, you add constraint for generic parameter T
it will start inferring specific literal type. The price for that is that it makes returned
applicable to subtypes of Kind
only.
enum Kind {
Apple,
Banana,
}
interface Wrapper<K> {
kind: K;
}
const returned = <K extends Kind>(kind: K): Wrapper<K> => ({
kind,
})
const theValue = returned(Kind.Apple);
const thisWorksNow: Wrapper<Kind.Apple> = theValue;
Upvotes: 3