From 3bdf36a7b80832758cae9aeb36d8776b17192035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 5 Feb 2023 11:07:36 +0100 Subject: [PATCH 1/2] Extend `isTupleLikeType` to also check if `.length` is a number literal type --- src/compiler/checker.ts | 5 ++++- .../reference/contextualTypeWithTuple.errors.txt | 8 +++++++- .../baselines/reference/contextualTypeWithTuple.js | 9 ++++++++- .../reference/contextualTypeWithTuple.symbols | 13 +++++++++++++ .../reference/contextualTypeWithTuple.types | 14 ++++++++++++++ .../types/tuple/contextualTypeWithTuple.ts | 7 ++++++- 6 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b1d258e6c2afd..c8bf02b4d61b5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22914,7 +22914,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTupleLikeType(type: Type): boolean { - return isTupleType(type) || !!getPropertyOfType(type, "0" as __String); + let lengthType; + return isTupleType(type) || + !!getPropertyOfType(type, "0" as __String) || + isArrayLikeType(type) && !!(lengthType = getTypeOfPropertyOfType(type, "length" as __String)) && everyType(lengthType, t => !!(t.flags & TypeFlags.NumberLiteral)); } function isArrayOrTupleLikeType(type: Type): boolean { diff --git a/tests/baselines/reference/contextualTypeWithTuple.errors.txt b/tests/baselines/reference/contextualTypeWithTuple.errors.txt index 809fbb1e5844b..32fa21d707d08 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.errors.txt +++ b/tests/baselines/reference/contextualTypeWithTuple.errors.txt @@ -68,4 +68,10 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(25,1): error TS23 !!! error TS2322: Type '[number, string | number]' is not assignable to type '[number, string]'. !!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. !!! error TS2322: Type 'string | number' is not assignable to type 'string'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. \ No newline at end of file +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + // repro from #29311 + type test1 = [...number[]] + type fixed1 = test1 & { length: 2 } + let var1: fixed1 = [0, 0] + \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypeWithTuple.js b/tests/baselines/reference/contextualTypeWithTuple.js index 3703174945e8a..dfb5d51e6888f 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.js +++ b/tests/baselines/reference/contextualTypeWithTuple.js @@ -23,7 +23,13 @@ var strStrTuple: [string, string] = ["foo", "bar", 5]; unionTuple = unionTuple1; unionTuple = unionTuple2; unionTuple2 = unionTuple; -numStrTuple = unionTuple3; +numStrTuple = unionTuple3; + +// repro from #29311 +type test1 = [...number[]] +type fixed1 = test1 & { length: 2 } +let var1: fixed1 = [0, 0] + //// [contextualTypeWithTuple.js] // no error @@ -56,3 +62,4 @@ unionTuple = unionTuple1; unionTuple = unionTuple2; unionTuple2 = unionTuple; numStrTuple = unionTuple3; +var var1 = [0, 0]; diff --git a/tests/baselines/reference/contextualTypeWithTuple.symbols b/tests/baselines/reference/contextualTypeWithTuple.symbols index 41ade2305f726..f5ab68aab0a8e 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.symbols +++ b/tests/baselines/reference/contextualTypeWithTuple.symbols @@ -80,3 +80,16 @@ numStrTuple = unionTuple3; >numStrTuple : Symbol(numStrTuple, Decl(contextualTypeWithTuple.ts, 1, 3)) >unionTuple3 : Symbol(unionTuple3, Decl(contextualTypeWithTuple.ts, 11, 3)) +// repro from #29311 +type test1 = [...number[]] +>test1 : Symbol(test1, Decl(contextualTypeWithTuple.ts, 24, 26)) + +type fixed1 = test1 & { length: 2 } +>fixed1 : Symbol(fixed1, Decl(contextualTypeWithTuple.ts, 27, 26)) +>test1 : Symbol(test1, Decl(contextualTypeWithTuple.ts, 24, 26)) +>length : Symbol(length, Decl(contextualTypeWithTuple.ts, 28, 23)) + +let var1: fixed1 = [0, 0] +>var1 : Symbol(var1, Decl(contextualTypeWithTuple.ts, 29, 3)) +>fixed1 : Symbol(fixed1, Decl(contextualTypeWithTuple.ts, 27, 26)) + diff --git a/tests/baselines/reference/contextualTypeWithTuple.types b/tests/baselines/reference/contextualTypeWithTuple.types index c3057f1e95a36..42d843753ff0d 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.types +++ b/tests/baselines/reference/contextualTypeWithTuple.types @@ -126,3 +126,17 @@ numStrTuple = unionTuple3; >numStrTuple : [number, string] >unionTuple3 : [number, string | number] +// repro from #29311 +type test1 = [...number[]] +>test1 : number[] + +type fixed1 = test1 & { length: 2 } +>fixed1 : test1 & { length: 2; } +>length : 2 + +let var1: fixed1 = [0, 0] +>var1 : fixed1 +>[0, 0] : [number, number] +>0 : 0 +>0 : 0 + diff --git a/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts b/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts index 9600ebcd6713d..4347a401119bb 100644 --- a/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts +++ b/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts @@ -22,4 +22,9 @@ var strStrTuple: [string, string] = ["foo", "bar", 5]; unionTuple = unionTuple1; unionTuple = unionTuple2; unionTuple2 = unionTuple; -numStrTuple = unionTuple3; \ No newline at end of file +numStrTuple = unionTuple3; + +// repro from #29311 +type test1 = [...number[]] +type fixed1 = test1 & { length: 2 } +let var1: fixed1 = [0, 0] From 2822e992545f6a1c889e8c00a0e565655010f5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 5 Feb 2023 13:47:40 +0100 Subject: [PATCH 2/2] Add an extra test case --- .../reference/contextualTypeWithTuple.errors.txt | 5 +++++ .../baselines/reference/contextualTypeWithTuple.js | 6 ++++++ .../reference/contextualTypeWithTuple.symbols | 13 +++++++++++++ .../reference/contextualTypeWithTuple.types | 11 +++++++++++ .../types/tuple/contextualTypeWithTuple.ts | 5 +++++ 5 files changed, 40 insertions(+) diff --git a/tests/baselines/reference/contextualTypeWithTuple.errors.txt b/tests/baselines/reference/contextualTypeWithTuple.errors.txt index 32fa21d707d08..47d12cffe5734 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.errors.txt +++ b/tests/baselines/reference/contextualTypeWithTuple.errors.txt @@ -74,4 +74,9 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(25,1): error TS23 type test1 = [...number[]] type fixed1 = test1 & { length: 2 } let var1: fixed1 = [0, 0] + + // #52551 + type EmptyTuple = [] + interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; } + const withExtra: MyEmptyTuple = [] \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypeWithTuple.js b/tests/baselines/reference/contextualTypeWithTuple.js index dfb5d51e6888f..7ff0a42514253 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.js +++ b/tests/baselines/reference/contextualTypeWithTuple.js @@ -29,6 +29,11 @@ numStrTuple = unionTuple3; type test1 = [...number[]] type fixed1 = test1 & { length: 2 } let var1: fixed1 = [0, 0] + +// #52551 +type EmptyTuple = [] +interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; } +const withExtra: MyEmptyTuple = [] //// [contextualTypeWithTuple.js] @@ -63,3 +68,4 @@ unionTuple = unionTuple2; unionTuple2 = unionTuple; numStrTuple = unionTuple3; var var1 = [0, 0]; +var withExtra = []; diff --git a/tests/baselines/reference/contextualTypeWithTuple.symbols b/tests/baselines/reference/contextualTypeWithTuple.symbols index f5ab68aab0a8e..ded268834dcb3 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.symbols +++ b/tests/baselines/reference/contextualTypeWithTuple.symbols @@ -93,3 +93,16 @@ let var1: fixed1 = [0, 0] >var1 : Symbol(var1, Decl(contextualTypeWithTuple.ts, 29, 3)) >fixed1 : Symbol(fixed1, Decl(contextualTypeWithTuple.ts, 27, 26)) +// #52551 +type EmptyTuple = [] +>EmptyTuple : Symbol(EmptyTuple, Decl(contextualTypeWithTuple.ts, 29, 25)) + +interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; } +>MyEmptyTuple : Symbol(MyEmptyTuple, Decl(contextualTypeWithTuple.ts, 32, 20)) +>EmptyTuple : Symbol(EmptyTuple, Decl(contextualTypeWithTuple.ts, 29, 25)) +>extraInfo : Symbol(MyEmptyTuple.extraInfo, Decl(contextualTypeWithTuple.ts, 33, 43)) + +const withExtra: MyEmptyTuple = [] +>withExtra : Symbol(withExtra, Decl(contextualTypeWithTuple.ts, 34, 5)) +>MyEmptyTuple : Symbol(MyEmptyTuple, Decl(contextualTypeWithTuple.ts, 32, 20)) + diff --git a/tests/baselines/reference/contextualTypeWithTuple.types b/tests/baselines/reference/contextualTypeWithTuple.types index 42d843753ff0d..e699d20e8e898 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.types +++ b/tests/baselines/reference/contextualTypeWithTuple.types @@ -140,3 +140,14 @@ let var1: fixed1 = [0, 0] >0 : 0 >0 : 0 +// #52551 +type EmptyTuple = [] +>EmptyTuple : [] + +interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; } +>extraInfo : any + +const withExtra: MyEmptyTuple = [] +>withExtra : MyEmptyTuple +>[] : [] + diff --git a/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts b/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts index 4347a401119bb..a02e5c839799c 100644 --- a/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts +++ b/tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts @@ -28,3 +28,8 @@ numStrTuple = unionTuple3; type test1 = [...number[]] type fixed1 = test1 & { length: 2 } let var1: fixed1 = [0, 0] + +// #52551 +type EmptyTuple = [] +interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; } +const withExtra: MyEmptyTuple = []