diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4a294a2474f26..fb42895d20e58 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25237,6 +25237,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (candidate === blockedStringType) { return; } + // without strictNullChecks an inference from an array of undefinedWideningType is still better than an inference from a widening null/undefined + // so we avoid deprioritization of those inferences when strictNullChecks are not enabled + if (strictNullChecks && isEmptyArrayLiteralType(candidate)) { + priority |= InferencePriority.ImplicitNever; + } if (inference.priority === undefined || priority < inference.priority) { inference.candidates = undefined; inference.contraCandidates = undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 34a2835822302..8e3411333ac30 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6817,11 +6817,12 @@ export const enum InferencePriority { PartialHomomorphicMappedType = 1 << 4, // Partial reverse inference for homomorphic mapped type MappedTypeConstraint = 1 << 5, // Reverse inference for mapped type ContravariantConditional = 1 << 6, // Conditional type in contravariant position - ReturnType = 1 << 7, // Inference made from return type of generic function - LiteralKeyof = 1 << 8, // Inference made from a string literal to a keyof T - NoConstraints = 1 << 9, // Don't infer from constraints of instantiable types - AlwaysStrict = 1 << 10, // Always use strict rules for contravariant inferences - MaxValue = 1 << 11, // Seed for inference priority tracking + ImplicitNever = 1 << 7, // Inference made from an implicit never type + ReturnType = 1 << 8, // Inference made from return type of generic function + LiteralKeyof = 1 << 9, // Inference made from a string literal to a keyof T + NoConstraints = 1 << 10, // Don't infer from constraints of instantiable types + AlwaysStrict = 1 << 11, // Always use strict rules for contravariant inferences + MaxValue = 1 << 12, // Seed for inference priority tracking PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates Circularity = -1, // Inference circularity (value less than all other priorities) diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index eddf759a20b84..bb395eb8f73ac 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -7360,12 +7360,13 @@ declare namespace ts { PartialHomomorphicMappedType = 16, MappedTypeConstraint = 32, ContravariantConditional = 64, - ReturnType = 128, - LiteralKeyof = 256, - NoConstraints = 512, - AlwaysStrict = 1024, - MaxValue = 2048, - PriorityImpliesCombination = 416, + ImplicitNever = 128, + ReturnType = 256, + LiteralKeyof = 512, + NoConstraints = 1024, + AlwaysStrict = 2048, + MaxValue = 4096, + PriorityImpliesCombination = 800, Circularity = -1, } interface FileExtensionInfo { diff --git a/tests/baselines/reference/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.symbols b/tests/baselines/reference/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.symbols new file mode 100644 index 0000000000000..4677d504b6bb1 --- /dev/null +++ b/tests/baselines/reference/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.symbols @@ -0,0 +1,73 @@ +//// [tests/cases/compiler/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts] //// + +=== mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54000 + +function foo(record: Record, entity: T) {} +>foo : Symbol(foo, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 2, 13)) +>record : Symbol(record, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 2, 16)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 2, 13)) +>entity : Symbol(entity, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 2, 42)) +>T : Symbol(T, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 2, 13)) + +type StringArrayRecord = Record; +>StringArrayRecord : Symbol(StringArrayRecord, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 2, 56)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + +function test() { +>test : Symbol(test, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 4, 50)) + + const working: Record = {}; +>working : Symbol(working, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 7, 7)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + foo(working, []); +>foo : Symbol(foo, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 0, 0)) +>working : Symbol(working, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 7, 7)) + + const working2: StringArrayRecord = {}; +>working2 : Symbol(working2, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 10, 7)) +>StringArrayRecord : Symbol(StringArrayRecord, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 2, 56)) + + foo(working2, []); +>foo : Symbol(foo, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 0, 0)) +>working2 : Symbol(working2, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 10, 7)) +} + +// showcase the same behavior with index signature + +function bar(record: { [k: string]: T }, entity: T) {} +>bar : Symbol(bar, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 12, 1)) +>T : Symbol(T, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 13)) +>record : Symbol(record, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 16)) +>k : Symbol(k, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 27)) +>T : Symbol(T, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 13)) +>entity : Symbol(entity, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 43)) +>T : Symbol(T, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 13)) + +type StringArrayIndexSignature = { [k: string]: string[] }; +>StringArrayIndexSignature : Symbol(StringArrayIndexSignature, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 57)) +>k : Symbol(k, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 18, 36)) + +function test2() { +>test2 : Symbol(test2, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 18, 59)) + + const working: { [k: string]: string[] } = {}; +>working : Symbol(working, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 21, 7)) +>k : Symbol(k, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 21, 20)) + + bar(working, []); +>bar : Symbol(bar, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 12, 1)) +>working : Symbol(working, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 21, 7)) + + const working2: StringArrayIndexSignature = {}; +>working2 : Symbol(working2, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 24, 7)) +>StringArrayIndexSignature : Symbol(StringArrayIndexSignature, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 16, 57)) + + bar(working2, []); +>bar : Symbol(bar, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 12, 1)) +>working2 : Symbol(working2, Decl(mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts, 24, 7)) +} + diff --git a/tests/baselines/reference/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.types b/tests/baselines/reference/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.types new file mode 100644 index 0000000000000..059928b0696af --- /dev/null +++ b/tests/baselines/reference/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.types @@ -0,0 +1,74 @@ +//// [tests/cases/compiler/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts] //// + +=== mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54000 + +function foo(record: Record, entity: T) {} +>foo : (record: Record, entity: T) => void +>record : Record +>entity : T + +type StringArrayRecord = Record; +>StringArrayRecord : { [x: string]: string[]; } + +function test() { +>test : () => void + + const working: Record = {}; +>working : Record +>{} : {} + + foo(working, []); +>foo(working, []) : void +>foo : (record: Record, entity: T) => void +>working : Record +>[] : never[] + + const working2: StringArrayRecord = {}; +>working2 : StringArrayRecord +>{} : {} + + foo(working2, []); +>foo(working2, []) : void +>foo : (record: Record, entity: T) => void +>working2 : StringArrayRecord +>[] : never[] +} + +// showcase the same behavior with index signature + +function bar(record: { [k: string]: T }, entity: T) {} +>bar : (record: { [k: string]: T; }, entity: T) => void +>record : { [k: string]: T; } +>k : string +>entity : T + +type StringArrayIndexSignature = { [k: string]: string[] }; +>StringArrayIndexSignature : { [k: string]: string[]; } +>k : string + +function test2() { +>test2 : () => void + + const working: { [k: string]: string[] } = {}; +>working : { [k: string]: string[]; } +>k : string +>{} : {} + + bar(working, []); +>bar(working, []) : void +>bar : (record: { [k: string]: T; }, entity: T) => void +>working : { [k: string]: string[]; } +>[] : never[] + + const working2: StringArrayIndexSignature = {}; +>working2 : StringArrayIndexSignature +>{} : {} + + bar(working2, []); +>bar(working2, []) : void +>bar : (record: { [k: string]: T; }, entity: T) => void +>working2 : StringArrayIndexSignature +>[] : never[] +} + diff --git a/tests/baselines/reference/unionOfClassCalls.js b/tests/baselines/reference/unionOfClassCalls.js index 3398d25f5be13..4085f6613a4c8 100644 --- a/tests/baselines/reference/unionOfClassCalls.js +++ b/tests/baselines/reference/unionOfClassCalls.js @@ -27,7 +27,6 @@ arr.map((a: number | string, index: number) => { return index }) -// This case still doesn't work because `reduce` has multiple overloads :( arr.reduce((acc: Array, a: number | string, index: number) => { return [] }, []) @@ -92,7 +91,6 @@ var arr2 = []; arr.map(function (a, index) { return index; }); -// This case still doesn't work because `reduce` has multiple overloads :( arr.reduce(function (acc, a, index) { return []; }, []); diff --git a/tests/baselines/reference/unionOfClassCalls.symbols b/tests/baselines/reference/unionOfClassCalls.symbols index 44bf8856cf042..ab080bf147d0d 100644 --- a/tests/baselines/reference/unionOfClassCalls.symbols +++ b/tests/baselines/reference/unionOfClassCalls.symbols @@ -67,15 +67,14 @@ arr.map((a: number | string, index: number) => { }) -// This case still doesn't work because `reduce` has multiple overloads :( arr.reduce((acc: Array, a: number | string, index: number) => { >arr.reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --) ... and 1 more) >arr : Symbol(arr, Decl(unionOfClassCalls.ts, 18, 5)) >reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --) ... and 1 more) ->acc : Symbol(acc, Decl(unionOfClassCalls.ts, 27, 12)) +>acc : Symbol(acc, Decl(unionOfClassCalls.ts, 26, 12)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 27, 31)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 27, 51)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 26, 31)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 26, 51)) return [] }, []) @@ -84,11 +83,11 @@ arr.forEach((a: number | string, index: number) => { >arr.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >arr : Symbol(arr, Decl(unionOfClassCalls.ts, 18, 5)) >forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 31, 13)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 31, 32)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 30, 13)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 30, 32)) return index ->index : Symbol(index, Decl(unionOfClassCalls.ts, 31, 32)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 30, 32)) }) @@ -96,11 +95,11 @@ arr1.map((a: number, index: number) => { >arr1.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) >arr1 : Symbol(arr1, Decl(unionOfClassCalls.ts, 19, 5)) >map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 35, 10)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 35, 20)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 34, 10)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 34, 20)) return index ->index : Symbol(index, Decl(unionOfClassCalls.ts, 35, 20)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 34, 20)) }) @@ -108,12 +107,12 @@ arr1.reduce((acc: number[], a: number, index: number) => { >arr1.reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >arr1 : Symbol(arr1, Decl(unionOfClassCalls.ts, 19, 5)) >reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->acc : Symbol(acc, Decl(unionOfClassCalls.ts, 39, 13)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 39, 27)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 39, 38)) +>acc : Symbol(acc, Decl(unionOfClassCalls.ts, 38, 13)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 38, 27)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 38, 38)) return [a] ->a : Symbol(a, Decl(unionOfClassCalls.ts, 39, 27)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 38, 27)) }, []) @@ -121,22 +120,22 @@ arr1.forEach((a: number, index: number) => { >arr1.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) >arr1 : Symbol(arr1, Decl(unionOfClassCalls.ts, 19, 5)) >forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 43, 14)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 43, 24)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 42, 14)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 42, 24)) return index ->index : Symbol(index, Decl(unionOfClassCalls.ts, 43, 24)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 42, 24)) }) arr2.map((a: string, index: number) => { >arr2.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) >arr2 : Symbol(arr2, Decl(unionOfClassCalls.ts, 20, 5)) >map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 46, 10)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 46, 21)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 45, 10)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 45, 21)) return index ->index : Symbol(index, Decl(unionOfClassCalls.ts, 46, 21)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 45, 21)) }) @@ -144,9 +143,9 @@ arr2.reduce((acc: string[], a: string, index: number) => { >arr2.reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >arr2 : Symbol(arr2, Decl(unionOfClassCalls.ts, 20, 5)) >reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->acc : Symbol(acc, Decl(unionOfClassCalls.ts, 50, 13)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 50, 27)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 50, 38)) +>acc : Symbol(acc, Decl(unionOfClassCalls.ts, 49, 13)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 49, 27)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 49, 38)) return [] }, []) @@ -155,54 +154,54 @@ arr2.forEach((a: string, index: number) => { >arr2.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) >arr2 : Symbol(arr2, Decl(unionOfClassCalls.ts, 20, 5)) >forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 54, 14)) ->index : Symbol(index, Decl(unionOfClassCalls.ts, 54, 24)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 53, 14)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 53, 24)) return index ->index : Symbol(index, Decl(unionOfClassCalls.ts, 54, 24)) +>index : Symbol(index, Decl(unionOfClassCalls.ts, 53, 24)) }) // from https://github.com/microsoft/TypeScript/issues/36307 declare class Foo { ->Foo : Symbol(Foo, Decl(unionOfClassCalls.ts, 56, 2)) +>Foo : Symbol(Foo, Decl(unionOfClassCalls.ts, 55, 2)) doThing(): Promise ->doThing : Symbol(Foo.doThing, Decl(unionOfClassCalls.ts, 60, 19)) +>doThing : Symbol(Foo.doThing, Decl(unionOfClassCalls.ts, 59, 19)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) } declare class Bar extends Foo { ->Bar : Symbol(Bar, Decl(unionOfClassCalls.ts, 62, 1)) ->Foo : Symbol(Foo, Decl(unionOfClassCalls.ts, 56, 2)) +>Bar : Symbol(Bar, Decl(unionOfClassCalls.ts, 61, 1)) +>Foo : Symbol(Foo, Decl(unionOfClassCalls.ts, 55, 2)) bar: number; ->bar : Symbol(Bar.bar, Decl(unionOfClassCalls.ts, 64, 31)) +>bar : Symbol(Bar.bar, Decl(unionOfClassCalls.ts, 63, 31)) } declare class Baz extends Foo { ->Baz : Symbol(Baz, Decl(unionOfClassCalls.ts, 66, 1)) ->Foo : Symbol(Foo, Decl(unionOfClassCalls.ts, 56, 2)) +>Baz : Symbol(Baz, Decl(unionOfClassCalls.ts, 65, 1)) +>Foo : Symbol(Foo, Decl(unionOfClassCalls.ts, 55, 2)) baz: number; ->baz : Symbol(Baz.baz, Decl(unionOfClassCalls.ts, 67, 31)) +>baz : Symbol(Baz.baz, Decl(unionOfClassCalls.ts, 66, 31)) } declare var a: Bar | Baz; ->a : Symbol(a, Decl(unionOfClassCalls.ts, 71, 11)) ->Bar : Symbol(Bar, Decl(unionOfClassCalls.ts, 62, 1)) ->Baz : Symbol(Baz, Decl(unionOfClassCalls.ts, 66, 1)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 70, 11)) +>Bar : Symbol(Bar, Decl(unionOfClassCalls.ts, 61, 1)) +>Baz : Symbol(Baz, Decl(unionOfClassCalls.ts, 65, 1)) // note, you must annotate `result` for now a.doThing().then((result: Bar | Baz) => { >a.doThing().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->a.doThing : Symbol(Foo.doThing, Decl(unionOfClassCalls.ts, 60, 19), Decl(unionOfClassCalls.ts, 60, 19)) ->a : Symbol(a, Decl(unionOfClassCalls.ts, 71, 11)) ->doThing : Symbol(Foo.doThing, Decl(unionOfClassCalls.ts, 60, 19), Decl(unionOfClassCalls.ts, 60, 19)) +>a.doThing : Symbol(Foo.doThing, Decl(unionOfClassCalls.ts, 59, 19), Decl(unionOfClassCalls.ts, 59, 19)) +>a : Symbol(a, Decl(unionOfClassCalls.ts, 70, 11)) +>doThing : Symbol(Foo.doThing, Decl(unionOfClassCalls.ts, 59, 19), Decl(unionOfClassCalls.ts, 59, 19)) >then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->result : Symbol(result, Decl(unionOfClassCalls.ts, 73, 18)) ->Bar : Symbol(Bar, Decl(unionOfClassCalls.ts, 62, 1)) ->Baz : Symbol(Baz, Decl(unionOfClassCalls.ts, 66, 1)) +>result : Symbol(result, Decl(unionOfClassCalls.ts, 72, 18)) +>Bar : Symbol(Bar, Decl(unionOfClassCalls.ts, 61, 1)) +>Baz : Symbol(Baz, Decl(unionOfClassCalls.ts, 65, 1)) // whatever }); diff --git a/tests/baselines/reference/unionOfClassCalls.types b/tests/baselines/reference/unionOfClassCalls.types index c31e22185f9c7..a1c349ad384ff 100644 --- a/tests/baselines/reference/unionOfClassCalls.types +++ b/tests/baselines/reference/unionOfClassCalls.types @@ -64,9 +64,8 @@ arr.map((a: number | string, index: number) => { }) -// This case still doesn't work because `reduce` has multiple overloads :( arr.reduce((acc: Array, a: number | string, index: number) => { ->arr.reduce((acc: Array, a: number | string, index: number) => { return []}, []) : never[] +>arr.reduce((acc: Array, a: number | string, index: number) => { return []}, []) : string[] >arr.reduce : { (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number; (callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; (callbackfn: (previousValue: U_1, currentValue: string, currentIndex: number, array: string[]) => U_1, initialValue: U_1): U_1; } >arr : number[] | string[] >reduce : { (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number; (callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; (callbackfn: (previousValue: U_1, currentValue: string, currentIndex: number, array: string[]) => U_1, initialValue: U_1): U_1; } @@ -154,7 +153,7 @@ arr2.map((a: string, index: number) => { }) arr2.reduce((acc: string[], a: string, index: number) => { ->arr2.reduce((acc: string[], a: string, index: number) => { return []}, []) : never[] +>arr2.reduce((acc: string[], a: string, index: number) => { return []}, []) : string[] >arr2.reduce : { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; (callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; } >arr2 : string[] >reduce : { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; (callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; } diff --git a/tests/cases/compiler/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts b/tests/cases/compiler/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts new file mode 100644 index 0000000000000..1a0726b982149 --- /dev/null +++ b/tests/cases/compiler/mappedTypeWithPrimitiveTypeParameterConstraintInferencePriority.ts @@ -0,0 +1,30 @@ +// @strict: true +// @noEmit: true + +// repro from https://github.com/microsoft/TypeScript/issues/54000 + +function foo(record: Record, entity: T) {} + +type StringArrayRecord = Record; + +function test() { + const working: Record = {}; + foo(working, []); + + const working2: StringArrayRecord = {}; + foo(working2, []); +} + +// showcase the same behavior with index signature + +function bar(record: { [k: string]: T }, entity: T) {} + +type StringArrayIndexSignature = { [k: string]: string[] }; + +function test2() { + const working: { [k: string]: string[] } = {}; + bar(working, []); + + const working2: StringArrayIndexSignature = {}; + bar(working2, []); +} diff --git a/tests/cases/compiler/unionOfClassCalls.ts b/tests/cases/compiler/unionOfClassCalls.ts index 509fbb4b46a6c..35aafce272b99 100644 --- a/tests/cases/compiler/unionOfClassCalls.ts +++ b/tests/cases/compiler/unionOfClassCalls.ts @@ -25,7 +25,6 @@ arr.map((a: number | string, index: number) => { return index }) -// This case still doesn't work because `reduce` has multiple overloads :( arr.reduce((acc: Array, a: number | string, index: number) => { return [] }, [])