Issue
I'm attempting to write a function that returns a value using generics and conditional types like so:
interface Foo<T> {
bar: T extends true ? string : undefined;
id: string;
}
interface Options<T> {
withBar?: T;
}
function createFoo<T extends boolean>({ withBar }: Options<T>): Foo<T> {
return {
id: 'foo',
...(withBar && { bar: 'baz' }),
};
}
The above throws the following type error:
Type '{ bar?: "baz" | undefined; id: string; }' is not assignable to type 'Foo<T>'.
Types of property 'bar' are incompatible.
Type '"baz" | undefined' is not assignable to type 'T extends true ? string : undefined'.
Type 'undefined' is not assignable to type 'T extends true ? string : undefined'.
Can someone help me understand why this is the case? I'm specifying that the type can be undefined, so it should be allow to be undefined.
Additionally I'd like to get the return type of the function given certain params without actually calling it. Is that possible?
e.g. ReturnType<typeof createFoo> won't give me the correct type for usage createFoo({ withBar: true }) because it doesn't know about the usage yet.
Solution
This is a common problem, the generic types do not resolve inside the function implementation. You could write a function overload to make your implementation work:
interface Foo<T> {
bar: T extends true ? string : undefined;
id: string;
}
interface Options<T> {
withBar?: T;
}
function createFoo<T extends boolean>({ withBar }: Options<T>): Foo<T>
function createFoo({ withBar }: Options<boolean>): Foo<true> | Foo<false> {
// The implementation works because the return type is allowed to be Foo<true> or Foo<false>
return {
id: 'foo',
...(withBar && { bar: 'baz' }),
};
}
// The first function overload is taken because it's the first one to match
// the call parameters
const foo = createFoo({ withBar: false }); // foo is of type Foo<false>
Answered By - Guerric P
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.