Reputation: 6854
I have an interface with optional parameter, and I want the return type to be based on whether the user passes this key:
interface Base {
id: string;
optional?: string;
}
declare function test<T extends Base>(value: T): T['optional'] extends undefined ? number : string;
test({ id: '3' })
But in the above example, the return type is string
. Is there any way to make it work?
test({ id: '3' }) => return type should be number
test({ id: '3', optional: '' }) => return type should be string
Upvotes: 0
Views: 986
Reputation: 187024
I think the problem here is that an optional property optional?: string
can actually be three different types once it's matched to the generic parameter.
string
as in { optional: 'foo' }
undefined
as in { optional: undefined }
never
as in {}
So in test({ id: '3' })
T['optional']
is never
, and T['optional'] extends undefined
is falsy.
It's probably simplest to check for the positive case string
instead:
T['optional'] extends string ? string : number;
However, you can avoid generic altogether with a simple overload.
declare function test(value: Base & { optional: string }): string;
declare function test(value: Base): number;
The first signature accepts a Base & { optional: string }
which would not match the case where optional
is omitted. The second signature catches any other valid Base
, which would be the undefined or missing case.
Upvotes: 2