From 9e90722564f354c765a9377152fc1488358324cf Mon Sep 17 00:00:00 2001 From: shivashis-adhikari <176213315+shivashis-adhikari@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:39:10 +0000 Subject: [PATCH 1/3] Add test for recursive tuple types with labeled rest elements The baselines show the current behavior: a labeled rest element such as '...rest: T[]' makes a recursive type alias report TS2456, while the same tuple without the label is accepted. --- ...siveTupleTypeLabeledRestElement.errors.txt | 64 +++++++++++++ .../recursiveTupleTypeLabeledRestElement.js | 71 ++++++++++++++ ...cursiveTupleTypeLabeledRestElement.symbols | 75 +++++++++++++++ ...recursiveTupleTypeLabeledRestElement.types | 92 +++++++++++++++++++ .../recursiveTupleTypeLabeledRestElement.ts | 41 +++++++++ 5 files changed, 343 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.js create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types create mode 100644 tsc/testdata/tests/cases/compiler/recursiveTupleTypeLabeledRestElement.ts diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt new file mode 100644 index 0000000000000..c06cb4210b3a3 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt @@ -0,0 +1,64 @@ +a.ts(2,13): error TS2456: Type alias 'Labeled' circularly references itself. +a.ts(4,13): error TS2456: Type alias 'LabeledAfterLabeled' circularly references itself. +a.ts(5,13): error TS2456: Type alias 'LabeledBeforeLabeled' circularly references itself. +a.ts(6,13): error TS2456: Type alias 'LabeledParenthesized' circularly references itself. +a.ts(8,13): error TS2456: Type alias 'DocNode' circularly references itself. +a.ts(13,13): error TS2456: Type alias 'Tree' circularly references itself. +a.ts(13,56): error TS2315: Type 'Tree' is not generic. +a.ts(17,19): error TS2315: Type 'Tree' is not generic. +a.ts(21,20): error TS2315: Type 'Tree' is not generic. +b.js(1,56): error TS2456: Type alias 'JSDocLabeled' circularly references itself. + + +==== a.ts (9 errors) ==== + export type Unlabeled = string | ["i", ...Unlabeled[]]; + export type Labeled = string | ["i", ...rest: Labeled[]]; + ~~~~~~~ +!!! error TS2456: Type alias 'Labeled' circularly references itself. + + export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2456: Type alias 'LabeledAfterLabeled' circularly references itself. + export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2456: Type alias 'LabeledBeforeLabeled' circularly references itself. + export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2456: Type alias 'LabeledParenthesized' circularly references itself. + + export type DocNode = + ~~~~~~~ +!!! error TS2456: Type alias 'DocNode' circularly references itself. + | string + | ["i", ...children: DocNode[]] + | ["li", index: number, ...children: DocNode[]]; + + export type Tree = T | [label: string, ...children: Tree[]]; + ~~~~ +!!! error TS2456: Type alias 'Tree' circularly references itself. + ~~~~~~~ +!!! error TS2315: Type 'Tree' is not generic. + + export const ok1: Labeled = ["i", "a", ["i", "b"]]; + export const ok2: DocNode = ["li", 0, "a", ["i"]]; + export const ok3: Tree = ["root", 1, ["leaf", 2]]; + ~~~~~~~~~~~~ +!!! error TS2315: Type 'Tree' is not generic. + + export const bad1: Labeled = ["i", 1]; + export const bad2: DocNode = ["li", "0"]; + export const bad3: Tree = ["root", "1"]; + ~~~~~~~~~~~~ +!!! error TS2315: Type 'Tree' is not generic. + +==== b.js (1 errors) ==== + /** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ + ~~~~~~~~~~~~ +!!! error TS2456: Type alias 'JSDocLabeled' circularly references itself. + + /** @type {JSDocLabeled} */ + export const ok4 = ["i", "a", ["i"]]; + + /** @type {JSDocLabeled} */ + export const bad4 = ["i", 1]; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.js b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.js new file mode 100644 index 0000000000000..99f0ba3c70084 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.js @@ -0,0 +1,71 @@ +//// [tests/cases/compiler/recursiveTupleTypeLabeledRestElement.ts] //// + +//// [a.ts] +export type Unlabeled = string | ["i", ...Unlabeled[]]; +export type Labeled = string | ["i", ...rest: Labeled[]]; + +export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; +export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; +export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; + +export type DocNode = + | string + | ["i", ...children: DocNode[]] + | ["li", index: number, ...children: DocNode[]]; + +export type Tree = T | [label: string, ...children: Tree[]]; + +export const ok1: Labeled = ["i", "a", ["i", "b"]]; +export const ok2: DocNode = ["li", 0, "a", ["i"]]; +export const ok3: Tree = ["root", 1, ["leaf", 2]]; + +export const bad1: Labeled = ["i", 1]; +export const bad2: DocNode = ["li", "0"]; +export const bad3: Tree = ["root", "1"]; + +//// [b.js] +/** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ + +/** @type {JSDocLabeled} */ +export const ok4 = ["i", "a", ["i"]]; + +/** @type {JSDocLabeled} */ +export const bad4 = ["i", 1]; + + +//// [a.js] +export const ok1 = ["i", "a", ["i", "b"]]; +export const ok2 = ["li", 0, "a", ["i"]]; +export const ok3 = ["root", 1, ["leaf", 2]]; +export const bad1 = ["i", 1]; +export const bad2 = ["li", "0"]; +export const bad3 = ["root", "1"]; +//// [b.js] +/** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ +/** @type {JSDocLabeled} */ +export const ok4 = ["i", "a", ["i"]]; +/** @type {JSDocLabeled} */ +export const bad4 = ["i", 1]; + + +//// [a.d.ts] +export type Unlabeled = string | ["i", ...Unlabeled[]]; +export type Labeled = string | ["i", ...rest: Labeled[]]; +export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; +export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; +export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; +export type DocNode = string | ["i", ...children: DocNode[]] | ["li", index: number, ...children: DocNode[]]; +export type Tree = T | [label: string, ...children: Tree[]]; +export declare const ok1: Labeled; +export declare const ok2: DocNode; +export declare const ok3: Tree; +export declare const bad1: Labeled; +export declare const bad2: DocNode; +export declare const bad3: Tree; +//// [b.d.ts] +/** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ +export type JSDocLabeled = string | ["i", ...rest: JSDocLabeled[]]; +/** @type {JSDocLabeled} */ +export declare const ok4: JSDocLabeled; +/** @type {JSDocLabeled} */ +export declare const bad4: JSDocLabeled; diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.symbols b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.symbols new file mode 100644 index 0000000000000..75837f7f899f2 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.symbols @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/recursiveTupleTypeLabeledRestElement.ts] //// + +=== a.ts === +export type Unlabeled = string | ["i", ...Unlabeled[]]; +>Unlabeled : Symbol(Unlabeled, Decl(a.ts, 0, 0)) +>Unlabeled : Symbol(Unlabeled, Decl(a.ts, 0, 0)) + +export type Labeled = string | ["i", ...rest: Labeled[]]; +>Labeled : Symbol(Labeled, Decl(a.ts, 0, 55)) +>Labeled : Symbol(Labeled, Decl(a.ts, 0, 55)) + +export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; +>LabeledAfterLabeled : Symbol(LabeledAfterLabeled, Decl(a.ts, 1, 57)) +>LabeledAfterLabeled : Symbol(LabeledAfterLabeled, Decl(a.ts, 1, 57)) + +export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; +>LabeledBeforeLabeled : Symbol(LabeledBeforeLabeled, Decl(a.ts, 3, 97)) +>LabeledBeforeLabeled : Symbol(LabeledBeforeLabeled, Decl(a.ts, 3, 97)) + +export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; +>LabeledParenthesized : Symbol(LabeledParenthesized, Decl(a.ts, 4, 97)) +>LabeledParenthesized : Symbol(LabeledParenthesized, Decl(a.ts, 4, 97)) + +export type DocNode = +>DocNode : Symbol(DocNode, Decl(a.ts, 5, 85)) + + | string + | ["i", ...children: DocNode[]] +>DocNode : Symbol(DocNode, Decl(a.ts, 5, 85)) + + | ["li", index: number, ...children: DocNode[]]; +>DocNode : Symbol(DocNode, Decl(a.ts, 5, 85)) + +export type Tree = T | [label: string, ...children: Tree[]]; +>Tree : Symbol(Tree, Decl(a.ts, 10, 52)) +>T : Symbol(T, Decl(a.ts, 12, 17)) +>T : Symbol(T, Decl(a.ts, 12, 17)) +>Tree : Symbol(Tree, Decl(a.ts, 10, 52)) +>T : Symbol(T, Decl(a.ts, 12, 17)) + +export const ok1: Labeled = ["i", "a", ["i", "b"]]; +>ok1 : Symbol(ok1, Decl(a.ts, 14, 12)) +>Labeled : Symbol(Labeled, Decl(a.ts, 0, 55)) + +export const ok2: DocNode = ["li", 0, "a", ["i"]]; +>ok2 : Symbol(ok2, Decl(a.ts, 15, 12)) +>DocNode : Symbol(DocNode, Decl(a.ts, 5, 85)) + +export const ok3: Tree = ["root", 1, ["leaf", 2]]; +>ok3 : Symbol(ok3, Decl(a.ts, 16, 12)) +>Tree : Symbol(Tree, Decl(a.ts, 10, 52)) + +export const bad1: Labeled = ["i", 1]; +>bad1 : Symbol(bad1, Decl(a.ts, 18, 12)) +>Labeled : Symbol(Labeled, Decl(a.ts, 0, 55)) + +export const bad2: DocNode = ["li", "0"]; +>bad2 : Symbol(bad2, Decl(a.ts, 19, 12)) +>DocNode : Symbol(DocNode, Decl(a.ts, 5, 85)) + +export const bad3: Tree = ["root", "1"]; +>bad3 : Symbol(bad3, Decl(a.ts, 20, 12)) +>Tree : Symbol(Tree, Decl(a.ts, 10, 52)) + +=== b.js === +/** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ + +/** @type {JSDocLabeled} */ +export const ok4 = ["i", "a", ["i"]]; +>ok4 : Symbol(ok4, Decl(b.js, 3, 12)) + +/** @type {JSDocLabeled} */ +export const bad4 = ["i", 1]; +>bad4 : Symbol(bad4, Decl(b.js, 6, 12)) + diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types new file mode 100644 index 0000000000000..df57bbe13267d --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types @@ -0,0 +1,92 @@ +//// [tests/cases/compiler/recursiveTupleTypeLabeledRestElement.ts] //// + +=== a.ts === +export type Unlabeled = string | ["i", ...Unlabeled[]]; +>Unlabeled : Unlabeled + +export type Labeled = string | ["i", ...rest: Labeled[]]; +>Labeled : any + +export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; +>LabeledAfterLabeled : any + +export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; +>LabeledBeforeLabeled : any + +export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; +>LabeledParenthesized : any + +export type DocNode = +>DocNode : any + + | string + | ["i", ...children: DocNode[]] + | ["li", index: number, ...children: DocNode[]]; + +export type Tree = T | [label: string, ...children: Tree[]]; +>Tree : any + +export const ok1: Labeled = ["i", "a", ["i", "b"]]; +>ok1 : any +>["i", "a", ["i", "b"]] : (string | string[])[] +>"i" : "i" +>"a" : "a" +>["i", "b"] : string[] +>"i" : "i" +>"b" : "b" + +export const ok2: DocNode = ["li", 0, "a", ["i"]]; +>ok2 : any +>["li", 0, "a", ["i"]] : (string | number | string[])[] +>"li" : "li" +>0 : 0 +>"a" : "a" +>["i"] : string[] +>"i" : "i" + +export const ok3: Tree = ["root", 1, ["leaf", 2]]; +>ok3 : any +>["root", 1, ["leaf", 2]] : (string | number | (string | number)[])[] +>"root" : "root" +>1 : 1 +>["leaf", 2] : (string | number)[] +>"leaf" : "leaf" +>2 : 2 + +export const bad1: Labeled = ["i", 1]; +>bad1 : any +>["i", 1] : (string | number)[] +>"i" : "i" +>1 : 1 + +export const bad2: DocNode = ["li", "0"]; +>bad2 : any +>["li", "0"] : string[] +>"li" : "li" +>"0" : "0" + +export const bad3: Tree = ["root", "1"]; +>bad3 : any +>["root", "1"] : string[] +>"root" : "root" +>"1" : "1" + +=== b.js === +/** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ + +/** @type {JSDocLabeled} */ +export const ok4 = ["i", "a", ["i"]]; +>ok4 : any +>["i", "a", ["i"]] : (string | string[])[] +>"i" : "i" +>"a" : "a" +>["i"] : string[] +>"i" : "i" + +/** @type {JSDocLabeled} */ +export const bad4 = ["i", 1]; +>bad4 : any +>["i", 1] : (string | number)[] +>"i" : "i" +>1 : 1 + diff --git a/tsc/testdata/tests/cases/compiler/recursiveTupleTypeLabeledRestElement.ts b/tsc/testdata/tests/cases/compiler/recursiveTupleTypeLabeledRestElement.ts new file mode 100644 index 0000000000000..a0bd30be74c20 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/recursiveTupleTypeLabeledRestElement.ts @@ -0,0 +1,41 @@ +// @strict: true +// @declaration: true +// @allowJs: true +// @checkJs: true +// @outDir: out + +// https://github.com/microsoft/TypeScript/issues/63584 + +// Labeling a rest element should not change whether a recursive tuple type is accepted. + +// @filename: a.ts +export type Unlabeled = string | ["i", ...Unlabeled[]]; +export type Labeled = string | ["i", ...rest: Labeled[]]; + +export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; +export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; +export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; + +export type DocNode = + | string + | ["i", ...children: DocNode[]] + | ["li", index: number, ...children: DocNode[]]; + +export type Tree = T | [label: string, ...children: Tree[]]; + +export const ok1: Labeled = ["i", "a", ["i", "b"]]; +export const ok2: DocNode = ["li", 0, "a", ["i"]]; +export const ok3: Tree = ["root", 1, ["leaf", 2]]; + +export const bad1: Labeled = ["i", 1]; +export const bad2: DocNode = ["li", "0"]; +export const bad3: Tree = ["root", "1"]; + +// @filename: b.js +/** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ + +/** @type {JSDocLabeled} */ +export const ok4 = ["i", "a", ["i"]]; + +/** @type {JSDocLabeled} */ +export const bad4 = ["i", 1]; From 0321a2ea33a02f801199cb0b484354a4432f81a5 Mon Sep 17 00:00:00 2001 From: shivashis-adhikari <176213315+shivashis-adhikari@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:39:24 +0000 Subject: [PATCH 2/3] Look through labeled rest elements when deferring recursive tuple types mayResolveTypeAlias decides whether a tuple type that may reference a type alias is deferred, which lets a type alias refer to itself through a tuple. An unlabeled rest element '...T[]' was checked by looking at T, but a labeled rest element '...name: T[]' is a NamedTupleMember, and that case only looked at the array type T[], for which the function returns false. The tuple was then resolved eagerly and reported a circular reference. A NamedTupleMember with a '...' token is now checked the same way as a RestType. --- tsc/internal/checker/checker.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 80a2afdf5d6b7..3ca86b0adb6a1 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -24012,10 +24012,15 @@ func (c *Checker) mayResolveTypeAlias(node *ast.Node) bool { return true case ast.KindTypeOperator: return node.AsTypeOperatorNode().Operator != ast.KindUniqueKeyword && c.mayResolveTypeAlias(node.Type()) - case ast.KindParenthesizedType, ast.KindOptionalType, ast.KindNamedTupleMember: + case ast.KindParenthesizedType, ast.KindOptionalType: + return c.mayResolveTypeAlias(node.Type()) + case ast.KindNamedTupleMember: + if node.AsNamedTupleMember().DotDotDotToken != nil { + return c.mayResolveRestElementTypeAlias(node.Type()) + } return c.mayResolveTypeAlias(node.Type()) case ast.KindRestType: - return node.Type().Kind != ast.KindArrayType || c.mayResolveTypeAlias(node.Type().AsArrayTypeNode().ElementType) + return c.mayResolveRestElementTypeAlias(node.Type()) case ast.KindUnionType: return core.Some(node.AsUnionTypeNode().Types.Nodes, c.mayResolveTypeAlias) case ast.KindIntersectionType: @@ -24029,6 +24034,12 @@ func (c *Checker) mayResolveTypeAlias(node *ast.Node) bool { return false } +// mayResolveRestElementTypeAlias checks the type of a rest element, labeled or not. A rest element '...T[]' +// contributes T itself to the tuple's element types, so the check looks through the array type. +func (c *Checker) mayResolveRestElementTypeAlias(node *ast.Node) bool { + return node.Kind != ast.KindArrayType || c.mayResolveTypeAlias(node.AsArrayTypeNode().ElementType) +} + func (c *Checker) createNormalizedTypeReference(target *Type, typeArguments []*Type) *Type { if target.objectFlags&ObjectFlagsTuple != 0 { return c.createNormalizedTupleType(target, typeArguments) From 3b2bbedc68a49a1a4ca999df50681582934d778a Mon Sep 17 00:00:00 2001 From: shivashis-adhikari <176213315+shivashis-adhikari@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:51:33 +0000 Subject: [PATCH 3/3] Accept baselines for labeled rest elements in recursive tuple types The labeled tuple types are now accepted like their unlabeled forms, and the invalid assignments to them report TS2322 instead of being unchecked. --- ...siveTupleTypeLabeledRestElement.errors.txt | 62 +++++++++---------- ...recursiveTupleTypeLabeledRestElement.types | 52 ++++++++-------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt index c06cb4210b3a3..cd16cd8d1e49e 100644 --- a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt +++ b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.errors.txt @@ -1,64 +1,64 @@ -a.ts(2,13): error TS2456: Type alias 'Labeled' circularly references itself. -a.ts(4,13): error TS2456: Type alias 'LabeledAfterLabeled' circularly references itself. -a.ts(5,13): error TS2456: Type alias 'LabeledBeforeLabeled' circularly references itself. -a.ts(6,13): error TS2456: Type alias 'LabeledParenthesized' circularly references itself. -a.ts(8,13): error TS2456: Type alias 'DocNode' circularly references itself. -a.ts(13,13): error TS2456: Type alias 'Tree' circularly references itself. -a.ts(13,56): error TS2315: Type 'Tree' is not generic. -a.ts(17,19): error TS2315: Type 'Tree' is not generic. -a.ts(21,20): error TS2315: Type 'Tree' is not generic. -b.js(1,56): error TS2456: Type alias 'JSDocLabeled' circularly references itself. +a.ts(19,14): error TS2322: Type '["i", number]' is not assignable to type 'Labeled'. + Type '["i", number]' is not assignable to type '["i", ...rest: Labeled[]]'. + Type at position 1 in source is not compatible with type at position 1 in target. + Type 'number' is not assignable to type 'Labeled'. +a.ts(20,14): error TS2322: Type '["li", string]' is not assignable to type 'DocNode'. + Type '["li", string]' is not assignable to type '["li", index: number, ...children: DocNode[]]'. + Type at position 1 in source is not compatible with type at position 1 in target. + Type 'string' is not assignable to type 'number'. +a.ts(21,44): error TS2322: Type 'string' is not assignable to type 'Tree'. +b.js(7,14): error TS2322: Type '["i", number]' is not assignable to type 'JSDocLabeled'. + Type '["i", number]' is not assignable to type '["i", ...rest: JSDocLabeled[]]'. + Type at position 1 in source is not compatible with type at position 1 in target. + Type 'number' is not assignable to type 'JSDocLabeled'. -==== a.ts (9 errors) ==== +==== a.ts (3 errors) ==== export type Unlabeled = string | ["i", ...Unlabeled[]]; export type Labeled = string | ["i", ...rest: Labeled[]]; - ~~~~~~~ -!!! error TS2456: Type alias 'Labeled' circularly references itself. export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; - ~~~~~~~~~~~~~~~~~~~ -!!! error TS2456: Type alias 'LabeledAfterLabeled' circularly references itself. export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2456: Type alias 'LabeledBeforeLabeled' circularly references itself. export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2456: Type alias 'LabeledParenthesized' circularly references itself. export type DocNode = - ~~~~~~~ -!!! error TS2456: Type alias 'DocNode' circularly references itself. | string | ["i", ...children: DocNode[]] | ["li", index: number, ...children: DocNode[]]; export type Tree = T | [label: string, ...children: Tree[]]; - ~~~~ -!!! error TS2456: Type alias 'Tree' circularly references itself. - ~~~~~~~ -!!! error TS2315: Type 'Tree' is not generic. export const ok1: Labeled = ["i", "a", ["i", "b"]]; export const ok2: DocNode = ["li", 0, "a", ["i"]]; export const ok3: Tree = ["root", 1, ["leaf", 2]]; - ~~~~~~~~~~~~ -!!! error TS2315: Type 'Tree' is not generic. export const bad1: Labeled = ["i", 1]; + ~~~~ +!!! error TS2322: Type '["i", number]' is not assignable to type 'Labeled'. +!!! error TS2322: Type '["i", number]' is not assignable to type '["i", ...rest: Labeled[]]'. +!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. +!!! error TS2322: Type 'number' is not assignable to type 'Labeled'. export const bad2: DocNode = ["li", "0"]; + ~~~~ +!!! error TS2322: Type '["li", string]' is not assignable to type 'DocNode'. +!!! error TS2322: Type '["li", string]' is not assignable to type '["li", index: number, ...children: DocNode[]]'. +!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. +!!! error TS2322: Type 'string' is not assignable to type 'number'. export const bad3: Tree = ["root", "1"]; - ~~~~~~~~~~~~ -!!! error TS2315: Type 'Tree' is not generic. + ~~~ +!!! error TS2322: Type 'string' is not assignable to type 'Tree'. ==== b.js (1 errors) ==== /** @typedef {string | ["i", ...rest: JSDocLabeled[]]} JSDocLabeled */ - ~~~~~~~~~~~~ -!!! error TS2456: Type alias 'JSDocLabeled' circularly references itself. /** @type {JSDocLabeled} */ export const ok4 = ["i", "a", ["i"]]; /** @type {JSDocLabeled} */ export const bad4 = ["i", 1]; + ~~~~ +!!! error TS2322: Type '["i", number]' is not assignable to type 'JSDocLabeled'. +!!! error TS2322: Type '["i", number]' is not assignable to type '["i", ...rest: JSDocLabeled[]]'. +!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. +!!! error TS2322: Type 'number' is not assignable to type 'JSDocLabeled'. \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types index df57bbe13267d..fbf6300913723 100644 --- a/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types +++ b/tsc/testdata/baselines/reference/compiler/recursiveTupleTypeLabeledRestElement.types @@ -5,69 +5,69 @@ export type Unlabeled = string | ["i", ...Unlabeled[]]; >Unlabeled : Unlabeled export type Labeled = string | ["i", ...rest: Labeled[]]; ->Labeled : any +>Labeled : Labeled export type LabeledAfterLabeled = string | ["li", index: number, ...rest: LabeledAfterLabeled[]]; ->LabeledAfterLabeled : any +>LabeledAfterLabeled : LabeledAfterLabeled export type LabeledBeforeLabeled = string | ["a", ...rest: LabeledBeforeLabeled[], last: number]; ->LabeledBeforeLabeled : any +>LabeledBeforeLabeled : LabeledBeforeLabeled export type LabeledParenthesized = string | ["a", ...rest: (LabeledParenthesized)[]]; ->LabeledParenthesized : any +>LabeledParenthesized : LabeledParenthesized export type DocNode = ->DocNode : any +>DocNode : DocNode | string | ["i", ...children: DocNode[]] | ["li", index: number, ...children: DocNode[]]; export type Tree = T | [label: string, ...children: Tree[]]; ->Tree : any +>Tree : Tree export const ok1: Labeled = ["i", "a", ["i", "b"]]; ->ok1 : any ->["i", "a", ["i", "b"]] : (string | string[])[] +>ok1 : Labeled +>["i", "a", ["i", "b"]] : ["i", string, ["i", string]] >"i" : "i" >"a" : "a" ->["i", "b"] : string[] +>["i", "b"] : ["i", string] >"i" : "i" >"b" : "b" export const ok2: DocNode = ["li", 0, "a", ["i"]]; ->ok2 : any ->["li", 0, "a", ["i"]] : (string | number | string[])[] +>ok2 : DocNode +>["li", 0, "a", ["i"]] : ["li", number, string, ["i"]] >"li" : "li" >0 : 0 >"a" : "a" ->["i"] : string[] +>["i"] : ["i"] >"i" : "i" export const ok3: Tree = ["root", 1, ["leaf", 2]]; ->ok3 : any ->["root", 1, ["leaf", 2]] : (string | number | (string | number)[])[] +>ok3 : Tree +>["root", 1, ["leaf", 2]] : [string, number, [string, number]] >"root" : "root" >1 : 1 ->["leaf", 2] : (string | number)[] +>["leaf", 2] : [string, number] >"leaf" : "leaf" >2 : 2 export const bad1: Labeled = ["i", 1]; ->bad1 : any ->["i", 1] : (string | number)[] +>bad1 : Labeled +>["i", 1] : ["i", number] >"i" : "i" >1 : 1 export const bad2: DocNode = ["li", "0"]; ->bad2 : any ->["li", "0"] : string[] +>bad2 : DocNode +>["li", "0"] : ["li", string] >"li" : "li" >"0" : "0" export const bad3: Tree = ["root", "1"]; ->bad3 : any ->["root", "1"] : string[] +>bad3 : Tree +>["root", "1"] : [string, string] >"root" : "root" >"1" : "1" @@ -76,17 +76,17 @@ export const bad3: Tree = ["root", "1"]; /** @type {JSDocLabeled} */ export const ok4 = ["i", "a", ["i"]]; ->ok4 : any ->["i", "a", ["i"]] : (string | string[])[] +>ok4 : JSDocLabeled +>["i", "a", ["i"]] : ["i", string, ["i"]] >"i" : "i" >"a" : "a" ->["i"] : string[] +>["i"] : ["i"] >"i" : "i" /** @type {JSDocLabeled} */ export const bad4 = ["i", 1]; ->bad4 : any ->["i", 1] : (string | number)[] +>bad4 : JSDocLabeled +>["i", 1] : ["i", number] >"i" : "i" >1 : 1