Closed
Description
TypeScript Version: 3.5.0-dev.20190509
Search Terms:
discriminate return type, keyof, extends
Expected behavior:
I want to discriminate the return type to "if a property in an object exists, return something different".
These are the 2 approaches I try, both don't work.
- Using
'select' extends keyof T
Playground Link
type Args = {
select?: boolean
}
interface Search {
findIt<T extends Args>(a: T): 'select' extends keyof T ? number : boolean
}
function Search(): Search {
const search = () => null
search.findIt = <T extends Args>(a: T) => a.select !== undefined ? 1 : false
return search
}
Error:
Type '{ (): any; findIt<T extends SomeArgs>(a: T): false | 1; }' is not assignable to type 'Search'.
Types of property 'findIt' are incompatible.
Type '<T extends SomeArgs>(a: T) => false | 1' is not assignable to type '<T extends SomeArgs>(a: Subset<T, SomeArgs>) => "select" extends keyof T ? number : boolean'.
Type 'false | 1' is not assignable to type '"select" extends keyof T ? number : boolean'.
Type 'false' is not assignable to type '"select" extends keyof T ? number : boolean'.ts(2322)
- Using
T extends ArgsWithSelect
Playground Link
type Args = {
select?: boolean
}
type ArgsWithSelect = {
select: boolean
}
interface Search {
findIt<T extends Args>(a: T): T extends ArgsWithSelect ? number : boolean
}
function Search(): Search {
const search = () => null
search.findIt = <T extends Args>(a: T) => a.select === undefined ? false : 1
return search
}
Error:
Type '{ (): any; findIt<T extends SomeArgs>(a: T): false | 1; }' is not assignable to type 'Search'.
Types of property 'findIt' are incompatible.
Type '<T extends SomeArgs>(a: T) => false | 1' is not assignable to type '<T extends SomeArgs>(a: T) => T extends SomeArgsWithSelect ? number : boolean'.
Type 'false | 1' is not assignable to type 'T extends SomeArgsWithSelect ? number : boolean'.
Type 'false' is not assignable to type 'T extends SomeArgsWithSelect ? number : boolean'
I'm running on [email protected]
.
Testing both interface definitions on a type level - they work perfectly. The only problem here is that TypeScript is not able to correctly infer the types from the ternary expression in the actual implementation.
In other words, I'm able to express this on a TypeSystem level, but I'm not able to provide an implementation that the compiler accepts.
Playground Link:
First Playground
Second Playground
Related Issues:
#28597