microsoft / microsoft/TypeScript
Narrowing empty string or false in generic misbehaves
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.4k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 117
Description
🔎 Search Terms
generic, narrowing, empty string, false, falsy
🕗 Version & Regression Information
This is the behavior in every version I tried, but it seems to behave a little worse with TS v4.2.3 and prior.
⏯ Playground Link
💻 Code
function func1<T extends number | null | undefined | false | ''>(x: number | T) {
return x || undefined;
}
function func2<T extends number | null | undefined | false | ''>(x: number | T) {
return x ? x > 0 ? x : -x : x;
}
function func3<T extends number | null | undefined | false | ''>(x: number | T) {
return x ? Math.abs(x) : x;
}
const x: number | undefined = func1('');
const y = func2(-3);
const z = func3(-3);
🙁 Actual behavior
The inferred return type of func1 can contain false or '' depending on T. It's wrong because x || undefined can never result in false or '' and thus should not be in the resulting type.
func2 fails type checking: Operator '>' cannot be applied to types 'number | NonNullable<T>' and 'number'.. It's wrong because the truthiness check should narrow x to number. (Note that func3 succeeds type checking because the signature of Math.abs seems to provide supplemental information which narrows x to number.)
🙂 Expected behavior
The inferred return type of func1 is should number | undefined, regardless of T.
func2 is expected to pass type checking, x having been narrowed to number with the truthiness check.
Additional information about the issue
All functions act 'correctly' if defined without the use of generics, but it's inadequate because the return type of func2 and func3 would always be number | null | undefined | false | '' regardless of argument type.
My actual use case is creating functions that transform numeric inputs and propagate falsy values. I've worked around this issue using type assertions in spots where narrowing misbehaves.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked TypeScript Playground example and reproduce the behavior in func1, func2, and func3 using the reported compiler versions. Trace the type-checking and control-flow narrowing for generic parameters under truthiness checks; done means func1 excludes false and '', while func2 type-checks with x narrowed to number.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100