diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 43dafe03456ab..ce707b6753eb8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26893,9 +26893,14 @@ namespace ts { return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); } // For other purposes (e.g. determining whether to produce literal types) we only - // incorporate inferences made from the return type in a function call. + // incorporate inferences made from the return type in a function call. We remove + // the 'boolean' type from the contextual type such that contextually typed boolean + // literals actually end up widening to 'boolean' (see #48363). if (inferenceContext.returnMapper) { - return instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper); + const type = instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper); + return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) && containsType((type as UnionType).types, regularTrueType) ? + filterType(type, t => t !== regularFalseType && t !== regularTrueType) : + type; } } } diff --git a/tests/baselines/reference/contextuallyTypedBooleanLiterals.js b/tests/baselines/reference/contextuallyTypedBooleanLiterals.js new file mode 100644 index 0000000000000..702a92440ad83 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedBooleanLiterals.js @@ -0,0 +1,55 @@ +//// [contextuallyTypedBooleanLiterals.ts] +// Repro from #48363 + +type Box = { + get: () => T, + set: (value: T) => void +} + +declare function box(value: T): Box; + +const bn1 = box(0); // Box +const bn2: Box = box(0); // Ok + +const bb1 = box(false); // Box +const bb2: Box = box(false); // Error, box not assignable to Box + +// Repro from #48150 + +interface Observable +{ + (): T; + (value: T): any; +} + +declare function observable(value: T): Observable; + +const x: Observable = observable(false); + + +//// [contextuallyTypedBooleanLiterals.js] +"use strict"; +// Repro from #48363 +var bn1 = box(0); // Box +var bn2 = box(0); // Ok +var bb1 = box(false); // Box +var bb2 = box(false); // Error, box not assignable to Box +var x = observable(false); + + +//// [contextuallyTypedBooleanLiterals.d.ts] +declare type Box = { + get: () => T; + set: (value: T) => void; +}; +declare function box(value: T): Box; +declare const bn1: Box; +declare const bn2: Box; +declare const bb1: Box; +declare const bb2: Box; +interface Observable { + (): T; + (value: T): any; +} +declare function observable(value: T): Observable; +declare const x: Observable; diff --git a/tests/baselines/reference/contextuallyTypedBooleanLiterals.symbols b/tests/baselines/reference/contextuallyTypedBooleanLiterals.symbols new file mode 100644 index 0000000000000..da1ec08b5bfcd --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedBooleanLiterals.symbols @@ -0,0 +1,70 @@ +=== tests/cases/compiler/contextuallyTypedBooleanLiterals.ts === +// Repro from #48363 + +type Box = { +>Box : Symbol(Box, Decl(contextuallyTypedBooleanLiterals.ts, 0, 0)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 2, 9)) + + get: () => T, +>get : Symbol(get, Decl(contextuallyTypedBooleanLiterals.ts, 2, 15)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 2, 9)) + + set: (value: T) => void +>set : Symbol(set, Decl(contextuallyTypedBooleanLiterals.ts, 3, 17)) +>value : Symbol(value, Decl(contextuallyTypedBooleanLiterals.ts, 4, 10)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 2, 9)) +} + +declare function box(value: T): Box; +>box : Symbol(box, Decl(contextuallyTypedBooleanLiterals.ts, 5, 1)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 7, 21)) +>value : Symbol(value, Decl(contextuallyTypedBooleanLiterals.ts, 7, 24)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 7, 21)) +>Box : Symbol(Box, Decl(contextuallyTypedBooleanLiterals.ts, 0, 0)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 7, 21)) + +const bn1 = box(0); // Box +>bn1 : Symbol(bn1, Decl(contextuallyTypedBooleanLiterals.ts, 9, 5)) +>box : Symbol(box, Decl(contextuallyTypedBooleanLiterals.ts, 5, 1)) + +const bn2: Box = box(0); // Ok +>bn2 : Symbol(bn2, Decl(contextuallyTypedBooleanLiterals.ts, 10, 5)) +>Box : Symbol(Box, Decl(contextuallyTypedBooleanLiterals.ts, 0, 0)) +>box : Symbol(box, Decl(contextuallyTypedBooleanLiterals.ts, 5, 1)) + +const bb1 = box(false); // Box +>bb1 : Symbol(bb1, Decl(contextuallyTypedBooleanLiterals.ts, 12, 5)) +>box : Symbol(box, Decl(contextuallyTypedBooleanLiterals.ts, 5, 1)) + +const bb2: Box = box(false); // Error, box not assignable to Box +>bb2 : Symbol(bb2, Decl(contextuallyTypedBooleanLiterals.ts, 13, 5)) +>Box : Symbol(Box, Decl(contextuallyTypedBooleanLiterals.ts, 0, 0)) +>box : Symbol(box, Decl(contextuallyTypedBooleanLiterals.ts, 5, 1)) + +// Repro from #48150 + +interface Observable +>Observable : Symbol(Observable, Decl(contextuallyTypedBooleanLiterals.ts, 13, 37)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 17, 21)) +{ + (): T; +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 17, 21)) + + (value: T): any; +>value : Symbol(value, Decl(contextuallyTypedBooleanLiterals.ts, 20, 3)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 17, 21)) +} + +declare function observable(value: T): Observable; +>observable : Symbol(observable, Decl(contextuallyTypedBooleanLiterals.ts, 21, 1)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 23, 28)) +>value : Symbol(value, Decl(contextuallyTypedBooleanLiterals.ts, 23, 31)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 23, 28)) +>Observable : Symbol(Observable, Decl(contextuallyTypedBooleanLiterals.ts, 13, 37)) +>T : Symbol(T, Decl(contextuallyTypedBooleanLiterals.ts, 23, 28)) + +const x: Observable = observable(false); +>x : Symbol(x, Decl(contextuallyTypedBooleanLiterals.ts, 25, 5)) +>Observable : Symbol(Observable, Decl(contextuallyTypedBooleanLiterals.ts, 13, 37)) +>observable : Symbol(observable, Decl(contextuallyTypedBooleanLiterals.ts, 21, 1)) + diff --git a/tests/baselines/reference/contextuallyTypedBooleanLiterals.types b/tests/baselines/reference/contextuallyTypedBooleanLiterals.types new file mode 100644 index 0000000000000..346a6e4fdb10d --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedBooleanLiterals.types @@ -0,0 +1,61 @@ +=== tests/cases/compiler/contextuallyTypedBooleanLiterals.ts === +// Repro from #48363 + +type Box = { +>Box : Box + + get: () => T, +>get : () => T + + set: (value: T) => void +>set : (value: T) => void +>value : T +} + +declare function box(value: T): Box; +>box : (value: T) => Box +>value : T + +const bn1 = box(0); // Box +>bn1 : Box +>box(0) : Box +>box : (value: T) => Box +>0 : 0 + +const bn2: Box = box(0); // Ok +>bn2 : Box +>box(0) : Box +>box : (value: T) => Box +>0 : 0 + +const bb1 = box(false); // Box +>bb1 : Box +>box(false) : Box +>box : (value: T) => Box +>false : false + +const bb2: Box = box(false); // Error, box not assignable to Box +>bb2 : Box +>box(false) : Box +>box : (value: T) => Box +>false : false + +// Repro from #48150 + +interface Observable +{ + (): T; + (value: T): any; +>value : T +} + +declare function observable(value: T): Observable; +>observable : (value: T) => Observable +>value : T + +const x: Observable = observable(false); +>x : Observable +>observable(false) : Observable +>observable : (value: T) => Observable +>false : false + diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt index aea21ac2504ac..c6d0b89667175 100644 --- a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt @@ -1,5 +1,4 @@ tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts(28,30): error TS2345: Argument of type 'string' is not assignable to parameter of type '"bar"'. -tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts(175,47): error TS2322: Type 'boolean' is not assignable to type 'true'. tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts(180,26): error TS2322: Type '{ state: State.A; }[] | { state: State.B; }[]' is not assignable to type '{ state: State.A; }[]'. Type '{ state: State.B; }[]' is not assignable to type '{ state: State.A; }[]'. Type '{ state: State.B; }' is not assignable to type '{ state: State.A; }'. @@ -7,7 +6,7 @@ tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts(180,26): error TS23 Type 'State.B' is not assignable to type 'State.A'. -==== tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts (3 errors) ==== +==== tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts (2 errors) ==== // Repros from #5487 function truePromise(): Promise { @@ -185,9 +184,6 @@ tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts(180,26): error TS23 declare function foldLeft(z: U, f: (acc: U, t: boolean) => U): U; let res: boolean = foldLeft(true, (acc, t) => acc && t); // Error - ~~~~~~~~ -!!! error TS2322: Type 'boolean' is not assignable to type 'true'. -!!! related TS6502 tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts:174:39: The expected type comes from the return type of this signature. enum State { A, B } type Foo = { state: State } diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types index bd2164e99e1d6..6eb2bbf32e681 100644 --- a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types @@ -461,14 +461,14 @@ declare function foldLeft(z: U, f: (acc: U, t: boolean) => U): U; let res: boolean = foldLeft(true, (acc, t) => acc && t); // Error >res : boolean ->foldLeft(true, (acc, t) => acc && t) : true +>foldLeft(true, (acc, t) => acc && t) : boolean >foldLeft : (z: U, f: (acc: U, t: boolean) => U) => U >true : true ->(acc, t) => acc && t : (acc: true, t: boolean) => boolean ->acc : true +>(acc, t) => acc && t : (acc: boolean, t: boolean) => boolean +>acc : boolean >t : boolean >acc && t : boolean ->acc : true +>acc : boolean >t : boolean enum State { A, B } diff --git a/tests/cases/compiler/contextuallyTypedBooleanLiterals.ts b/tests/cases/compiler/contextuallyTypedBooleanLiterals.ts new file mode 100644 index 0000000000000..8cbe5f64def4b --- /dev/null +++ b/tests/cases/compiler/contextuallyTypedBooleanLiterals.ts @@ -0,0 +1,32 @@ +// @strict: true +// @declaration: true + +// @strict: true +// @declaration: true + +// Repro from #48363 + +type Box = { + get: () => T, + set: (value: T) => void +} + +declare function box(value: T): Box; + +const bn1 = box(0); // Box +const bn2: Box = box(0); // Ok + +const bb1 = box(false); // Box +const bb2: Box = box(false); // Error, box not assignable to Box + +// Repro from #48150 + +interface Observable +{ + (): T; + (value: T): any; +} + +declare function observable(value: T): Observable; + +const x: Observable = observable(false);