Closed
Description
TypeScript Version: 3.0.0-dev.20180705
Search Terms: false/true loosened/expanded/loses specificity into boolean
Code
type Foo = FooBase | FooArray;
type FooBase = string | false;
type FooArray = FooBase[];
declare let foo1: Foo;
declare let foo2: Foo;
foo1 = [...Array.isArray(foo2) ? foo2 : [foo2]];
Expected behavior:
No error.. In the else clause, [foo2]
, it retains string | false
so Array<string | false>
. Logically since everything is taking place in the typings layer, foo2
should still be strongly bounded to false
and will never be true
.
Actual behavior:
Errors. In the else clause, [foo2]
, it expanded/loosened to string | boolean
so Array<string | boolean>
.
tmp.ts:7:1 - error TS2322: Type '(string | boolean)[]' is not assignable to type 'Foo'.
Type '(string | boolean)[]' is not assignable to type 'FooBase[]'.
Type 'string | boolean' is not assignable to type 'FooBase'.
Type 'true' is not assignable to type 'FooBase'.
7 foo1 = [...Array.isArray(foo2) ? foo2 : [foo2]];
~~~~
Playground Link: Link
Related Issues:
Activity
[-]Type of `false` unexpectedly loosens into type `boolean`[/-][+]Type of `false` unexpectedly widens into type `boolean`[/+]pedro-pedrosa commentedon Jul 6, 2018
Possibly related to this:
The return type of
trySomething
is{ result: boolean; message: string; } | { result: boolean; message?: undefined; }
while it should be{ result: false; message: string; } | { result: true; message?: undefined; }
If I use
strictNullChecks
and try to usea.message
I will get an error saying it's possibly undefined.Playground link
Ghabriel commentedon Jul 6, 2018
@pedro-pedrosa I don't think it's related, TS always widens literals like that unless you do something like this, which works:
pedro-pedrosa commentedon Jul 6, 2018
Okay that probably makes some sense, typescript probably doesn't want to make the type too strict as users of the function may want to write values to the return value of the function.
cliffkoh commentedon Jul 6, 2018
Note that there isn't a bug with string literal types, only false/true into boolean
This works. type of
[foo2]
in the conditional does not get widened intostring | string
.ahejlsberg commentedon Jul 6, 2018
This is an issue resulting from two separate factors:
true
andfalse
literal types and enum literal types are always considered widening.Because the array literal
[foo2]
occurs in a spread expression it isn't contextually typed byFooBase
(the type offoo1
) and therefore thestring | false
type is widened tostring | boolean
. This very similar assignment has no issues because the contextual type propagates appropriately:To fix this issue we need to propagate contextual types into spread expressions.
[-]Type of `false` unexpectedly widens into type `boolean`[/-][+]Literal type `false` unexpectedly widens into type `boolean`[/+]CS-Jfilmer commentedon Mar 5, 2020
Sorry, I feel like the answers I need are in this / #22596 but I can't grok it for the life of me
Is it that "true" means "boolean" if used in certain contexts to support
But I just tried that and ts seems to think that x is just true not a boolean, idk. Anyway is there anyway to have the above example work without having to use
true as true
?