From 3a903b8a283910ca6fdcc4989a0d4b0311b137fb Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 26 Nov 2020 21:19:15 +0200 Subject: [PATCH 1/6] fix(41653): convert arrow function to function expression that used as destructure initializer --- src/compiler/transformers/destructuring.ts | 2 +- ...indingPatternAndAssignment6(target=es5).js | 18 +++++++ ...gPatternAndAssignment6(target=es5).symbols | 27 +++++++++++ ...ingPatternAndAssignment6(target=es5).types | 36 ++++++++++++++ ...ingPatternAndAssignment6(target=esnext).js | 17 +++++++ ...tternAndAssignment6(target=esnext).symbols | 27 +++++++++++ ...PatternAndAssignment6(target=esnext).types | 36 ++++++++++++++ ...indingPatternAndAssignment7(target=es5).js | 22 +++++++++ ...gPatternAndAssignment7(target=es5).symbols | 38 +++++++++++++++ ...ingPatternAndAssignment7(target=es5).types | 47 ++++++++++++++++++ ...ingPatternAndAssignment7(target=esnext).js | 21 ++++++++ ...tternAndAssignment7(target=esnext).symbols | 38 +++++++++++++++ ...PatternAndAssignment7(target=esnext).types | 47 ++++++++++++++++++ ...indingPatternAndAssignment8(target=es5).js | 21 ++++++++ ...gPatternAndAssignment8(target=es5).symbols | 38 +++++++++++++++ ...ingPatternAndAssignment8(target=es5).types | 48 +++++++++++++++++++ ...ingPatternAndAssignment8(target=esnext).js | 20 ++++++++ ...tternAndAssignment8(target=esnext).symbols | 38 +++++++++++++++ ...PatternAndAssignment8(target=esnext).types | 48 +++++++++++++++++++ ...uringObjectBindingPatternAndAssignment6.ts | 9 ++++ ...uringObjectBindingPatternAndAssignment7.ts | 10 ++++ ...uringObjectBindingPatternAndAssignment8.ts | 10 ++++ 22 files changed, 617 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).js create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).symbols create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).types create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).js create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).symbols create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).types create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).js create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).symbols create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).types create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).js create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).symbols create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).types create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).js create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).symbols create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).types create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).js create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).symbols create mode 100644 tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).types create mode 100644 tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts create mode 100644 tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts create mode 100644 tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 484cee5e497..0e7eaac22c9 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -199,7 +199,7 @@ namespace ts { bindingOrAssignmentElementContainsNonLiteralComputedName(node))) { // If the right-hand value of the assignment is also an assignment target then // we need to cache the right-hand value. - initializer = ensureIdentifier(flattenContext, initializer, /*reuseIdentifierExpressions*/ false, initializer); + initializer = ensureIdentifier(flattenContext, visitNode(initializer, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, initializer); node = context.factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, initializer); } } diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).js b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).js new file mode 100644 index 00000000000..7cd6b2f7868 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).js @@ -0,0 +1,18 @@ +//// [destructuringObjectBindingPatternAndAssignment6.ts] +const a = "a"; +const b = "b"; + +const { [a]: aVal, [b]: bVal } = (() => { + return { [a]: 1, [b]: 1 }; +})(); +console.log(aVal, bVal); + + +//// [destructuringObjectBindingPatternAndAssignment6.js] +var a = "a"; +var b = "b"; +var _a = (function () { + var _a; + return _a = {}, _a[a] = 1, _a[b] = 1, _a; +})(), _b = a, aVal = _a[_b], _c = b, bVal = _a[_c]; +console.log(aVal, bVal); diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).symbols b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).symbols new file mode 100644 index 00000000000..f1559af2a19 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts === +const a = "a"; +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 0, 5)) + +const b = "b"; +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 1, 5)) + +const { [a]: aVal, [b]: bVal } = (() => { +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 0, 5)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 7)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 1, 5)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 18)) + + return { [a]: 1, [b]: 1 }; +>[a] : Symbol([a], Decl(destructuringObjectBindingPatternAndAssignment6.ts, 4, 9)) +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 0, 5)) +>[b] : Symbol([b], Decl(destructuringObjectBindingPatternAndAssignment6.ts, 4, 17)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 1, 5)) + +})(); +console.log(aVal, bVal); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 7)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 18)) + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).types b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).types new file mode 100644 index 00000000000..d52c62c7c02 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=es5).types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts === +const a = "a"; +>a : "a" +>"a" : "a" + +const b = "b"; +>b : "b" +>"b" : "b" + +const { [a]: aVal, [b]: bVal } = (() => { +>a : "a" +>aVal : number +>b : "b" +>bVal : number +>(() => { return { [a]: 1, [b]: 1 };})() : { a: number; b: number; } +>(() => { return { [a]: 1, [b]: 1 };}) : () => { a: number; b: number; } +>() => { return { [a]: 1, [b]: 1 };} : () => { a: number; b: number; } + + return { [a]: 1, [b]: 1 }; +>{ [a]: 1, [b]: 1 } : { a: number; b: number; } +>[a] : number +>a : "a" +>1 : 1 +>[b] : number +>b : "b" +>1 : 1 + +})(); +console.log(aVal, bVal); +>console.log(aVal, bVal) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>aVal : number +>bVal : number + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).js b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).js new file mode 100644 index 00000000000..dd88a36436b --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).js @@ -0,0 +1,17 @@ +//// [destructuringObjectBindingPatternAndAssignment6.ts] +const a = "a"; +const b = "b"; + +const { [a]: aVal, [b]: bVal } = (() => { + return { [a]: 1, [b]: 1 }; +})(); +console.log(aVal, bVal); + + +//// [destructuringObjectBindingPatternAndAssignment6.js] +const a = "a"; +const b = "b"; +const { [a]: aVal, [b]: bVal } = (() => { + return { [a]: 1, [b]: 1 }; +})(); +console.log(aVal, bVal); diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).symbols b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).symbols new file mode 100644 index 00000000000..f1559af2a19 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts === +const a = "a"; +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 0, 5)) + +const b = "b"; +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 1, 5)) + +const { [a]: aVal, [b]: bVal } = (() => { +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 0, 5)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 7)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 1, 5)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 18)) + + return { [a]: 1, [b]: 1 }; +>[a] : Symbol([a], Decl(destructuringObjectBindingPatternAndAssignment6.ts, 4, 9)) +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 0, 5)) +>[b] : Symbol([b], Decl(destructuringObjectBindingPatternAndAssignment6.ts, 4, 17)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 1, 5)) + +})(); +console.log(aVal, bVal); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 7)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment6.ts, 3, 18)) + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).types b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).types new file mode 100644 index 00000000000..d52c62c7c02 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment6(target=esnext).types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts === +const a = "a"; +>a : "a" +>"a" : "a" + +const b = "b"; +>b : "b" +>"b" : "b" + +const { [a]: aVal, [b]: bVal } = (() => { +>a : "a" +>aVal : number +>b : "b" +>bVal : number +>(() => { return { [a]: 1, [b]: 1 };})() : { a: number; b: number; } +>(() => { return { [a]: 1, [b]: 1 };}) : () => { a: number; b: number; } +>() => { return { [a]: 1, [b]: 1 };} : () => { a: number; b: number; } + + return { [a]: 1, [b]: 1 }; +>{ [a]: 1, [b]: 1 } : { a: number; b: number; } +>[a] : number +>a : "a" +>1 : 1 +>[b] : number +>b : "b" +>1 : 1 + +})(); +console.log(aVal, bVal); +>console.log(aVal, bVal) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>aVal : number +>bVal : number + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).js b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).js new file mode 100644 index 00000000000..4ac0cadebbf --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).js @@ -0,0 +1,22 @@ +//// [destructuringObjectBindingPatternAndAssignment7.ts] +enum K { + a = "a", + b = "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); + + +//// [destructuringObjectBindingPatternAndAssignment7.js] +var K; +(function (K) { + K["a"] = "a"; + K["b"] = "b"; +})(K || (K = {})); +var _a = (function () { + var _a; + return _a = {}, _a[K.a] = 1, _a[K.b] = 1, _a; +})(), _b = K.a, aVal = _a[_b], _c = K.b, bVal = _a[_c]; +console.log(aVal, bVal); diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).symbols b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).symbols new file mode 100644 index 00000000000..3e565f3e09a --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).symbols @@ -0,0 +1,38 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts === +enum K { +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) + + a = "a", +>a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) + + b = "b" +>b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 7)) +>K.b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 20)) + + return { [K.a]: 1, [K.b]: 1 }; +>[K.a] : Symbol([K.a], Decl(destructuringObjectBindingPatternAndAssignment7.ts, 5, 9)) +>K.a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>[K.b] : Symbol([K.b], Decl(destructuringObjectBindingPatternAndAssignment7.ts, 5, 19)) +>K.b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) + +})(); +console.log(aVal, bVal); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 7)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 20)) + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).types b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).types new file mode 100644 index 00000000000..3bae2143965 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=es5).types @@ -0,0 +1,47 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts === +enum K { +>K : K + + a = "a", +>a : K.a +>"a" : "a" + + b = "b" +>b : K.b +>"b" : "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : K.a +>K : typeof K +>a : K.a +>aVal : number +>K.b : K.b +>K : typeof K +>b : K.b +>bVal : number +>(() => { return { [K.a]: 1, [K.b]: 1 };})() : { a: number; b: number; } +>(() => { return { [K.a]: 1, [K.b]: 1 };}) : () => { a: number; b: number; } +>() => { return { [K.a]: 1, [K.b]: 1 };} : () => { a: number; b: number; } + + return { [K.a]: 1, [K.b]: 1 }; +>{ [K.a]: 1, [K.b]: 1 } : { a: number; b: number; } +>[K.a] : number +>K.a : K.a +>K : typeof K +>a : K.a +>1 : 1 +>[K.b] : number +>K.b : K.b +>K : typeof K +>b : K.b +>1 : 1 + +})(); +console.log(aVal, bVal); +>console.log(aVal, bVal) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>aVal : number +>bVal : number + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).js b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).js new file mode 100644 index 00000000000..8a7cf6ddbbb --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).js @@ -0,0 +1,21 @@ +//// [destructuringObjectBindingPatternAndAssignment7.ts] +enum K { + a = "a", + b = "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); + + +//// [destructuringObjectBindingPatternAndAssignment7.js] +var K; +(function (K) { + K["a"] = "a"; + K["b"] = "b"; +})(K || (K = {})); +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).symbols b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).symbols new file mode 100644 index 00000000000..3e565f3e09a --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).symbols @@ -0,0 +1,38 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts === +enum K { +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) + + a = "a", +>a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) + + b = "b" +>b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 7)) +>K.b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 20)) + + return { [K.a]: 1, [K.b]: 1 }; +>[K.a] : Symbol([K.a], Decl(destructuringObjectBindingPatternAndAssignment7.ts, 5, 9)) +>K.a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>a : Symbol(K.a, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 8)) +>[K.b] : Symbol([K.b], Decl(destructuringObjectBindingPatternAndAssignment7.ts, 5, 19)) +>K.b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 0, 0)) +>b : Symbol(K.b, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 1, 12)) + +})(); +console.log(aVal, bVal); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 7)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment7.ts, 4, 20)) + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).types b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).types new file mode 100644 index 00000000000..3bae2143965 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment7(target=esnext).types @@ -0,0 +1,47 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts === +enum K { +>K : K + + a = "a", +>a : K.a +>"a" : "a" + + b = "b" +>b : K.b +>"b" : "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : K.a +>K : typeof K +>a : K.a +>aVal : number +>K.b : K.b +>K : typeof K +>b : K.b +>bVal : number +>(() => { return { [K.a]: 1, [K.b]: 1 };})() : { a: number; b: number; } +>(() => { return { [K.a]: 1, [K.b]: 1 };}) : () => { a: number; b: number; } +>() => { return { [K.a]: 1, [K.b]: 1 };} : () => { a: number; b: number; } + + return { [K.a]: 1, [K.b]: 1 }; +>{ [K.a]: 1, [K.b]: 1 } : { a: number; b: number; } +>[K.a] : number +>K.a : K.a +>K : typeof K +>a : K.a +>1 : 1 +>[K.b] : number +>K.b : K.b +>K : typeof K +>b : K.b +>1 : 1 + +})(); +console.log(aVal, bVal); +>console.log(aVal, bVal) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>aVal : number +>bVal : number + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).js b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).js new file mode 100644 index 00000000000..66965f5404a --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).js @@ -0,0 +1,21 @@ +//// [destructuringObjectBindingPatternAndAssignment8.ts] +const K = { + a: "a", + b: "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); + + +//// [destructuringObjectBindingPatternAndAssignment8.js] +var K = { + a: "a", + b: "b" +}; +var _a = (function () { + var _a; + return _a = {}, _a[K.a] = 1, _a[K.b] = 1, _a; +})(), _b = K.a, aVal = _a[_b], _c = K.b, bVal = _a[_c]; +console.log(aVal, bVal); diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).symbols b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).symbols new file mode 100644 index 00000000000..fd70bde23df --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).symbols @@ -0,0 +1,38 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts === +const K = { +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) + + a: "a", +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) + + b: "b" +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 7)) +>K.b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 20)) + + return { [K.a]: 1, [K.b]: 1 }; +>[K.a] : Symbol([K.a], Decl(destructuringObjectBindingPatternAndAssignment8.ts, 5, 9)) +>K.a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>[K.b] : Symbol([K.b], Decl(destructuringObjectBindingPatternAndAssignment8.ts, 5, 19)) +>K.b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) + +})(); +console.log(aVal, bVal); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 7)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 20)) + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).types b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).types new file mode 100644 index 00000000000..c13e856f989 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=es5).types @@ -0,0 +1,48 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts === +const K = { +>K : { a: string; b: string; } +>{ a: "a", b: "b"} : { a: string; b: string; } + + a: "a", +>a : string +>"a" : "a" + + b: "b" +>b : string +>"b" : "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : string +>K : { a: string; b: string; } +>a : string +>aVal : number +>K.b : string +>K : { a: string; b: string; } +>b : string +>bVal : number +>(() => { return { [K.a]: 1, [K.b]: 1 };})() : { [x: string]: number; } +>(() => { return { [K.a]: 1, [K.b]: 1 };}) : () => { [x: string]: number; } +>() => { return { [K.a]: 1, [K.b]: 1 };} : () => { [x: string]: number; } + + return { [K.a]: 1, [K.b]: 1 }; +>{ [K.a]: 1, [K.b]: 1 } : { [x: string]: number; } +>[K.a] : number +>K.a : string +>K : { a: string; b: string; } +>a : string +>1 : 1 +>[K.b] : number +>K.b : string +>K : { a: string; b: string; } +>b : string +>1 : 1 + +})(); +console.log(aVal, bVal); +>console.log(aVal, bVal) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>aVal : number +>bVal : number + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).js b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).js new file mode 100644 index 00000000000..728988643f5 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).js @@ -0,0 +1,20 @@ +//// [destructuringObjectBindingPatternAndAssignment8.ts] +const K = { + a: "a", + b: "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); + + +//// [destructuringObjectBindingPatternAndAssignment8.js] +const K = { + a: "a", + b: "b" +}; +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).symbols b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).symbols new file mode 100644 index 00000000000..fd70bde23df --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).symbols @@ -0,0 +1,38 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts === +const K = { +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) + + a: "a", +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) + + b: "b" +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 7)) +>K.b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 20)) + + return { [K.a]: 1, [K.b]: 1 }; +>[K.a] : Symbol([K.a], Decl(destructuringObjectBindingPatternAndAssignment8.ts, 5, 9)) +>K.a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>a : Symbol(a, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 11)) +>[K.b] : Symbol([K.b], Decl(destructuringObjectBindingPatternAndAssignment8.ts, 5, 19)) +>K.b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) +>K : Symbol(K, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 0, 5)) +>b : Symbol(b, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 1, 11)) + +})(); +console.log(aVal, bVal); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>aVal : Symbol(aVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 7)) +>bVal : Symbol(bVal, Decl(destructuringObjectBindingPatternAndAssignment8.ts, 4, 20)) + diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).types b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).types new file mode 100644 index 00000000000..c13e856f989 --- /dev/null +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment8(target=esnext).types @@ -0,0 +1,48 @@ +=== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts === +const K = { +>K : { a: string; b: string; } +>{ a: "a", b: "b"} : { a: string; b: string; } + + a: "a", +>a : string +>"a" : "a" + + b: "b" +>b : string +>"b" : "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { +>K.a : string +>K : { a: string; b: string; } +>a : string +>aVal : number +>K.b : string +>K : { a: string; b: string; } +>b : string +>bVal : number +>(() => { return { [K.a]: 1, [K.b]: 1 };})() : { [x: string]: number; } +>(() => { return { [K.a]: 1, [K.b]: 1 };}) : () => { [x: string]: number; } +>() => { return { [K.a]: 1, [K.b]: 1 };} : () => { [x: string]: number; } + + return { [K.a]: 1, [K.b]: 1 }; +>{ [K.a]: 1, [K.b]: 1 } : { [x: string]: number; } +>[K.a] : number +>K.a : string +>K : { a: string; b: string; } +>a : string +>1 : 1 +>[K.b] : number +>K.b : string +>K : { a: string; b: string; } +>b : string +>1 : 1 + +})(); +console.log(aVal, bVal); +>console.log(aVal, bVal) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>aVal : number +>bVal : number + diff --git a/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts new file mode 100644 index 00000000000..dd790306d90 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment6.ts @@ -0,0 +1,9 @@ +// @target: es5,esnext + +const a = "a"; +const b = "b"; + +const { [a]: aVal, [b]: bVal } = (() => { + return { [a]: 1, [b]: 1 }; +})(); +console.log(aVal, bVal); diff --git a/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts new file mode 100644 index 00000000000..b4d32d11421 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment7.ts @@ -0,0 +1,10 @@ +// @target: es5,esnext + +enum K { + a = "a", + b = "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); diff --git a/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts new file mode 100644 index 00000000000..e502f5871c1 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment8.ts @@ -0,0 +1,10 @@ +// @target: es5,esnext + +const K = { + a: "a", + b: "b" +} +const { [K.a]: aVal, [K.b]: bVal } = (() => { + return { [K.a]: 1, [K.b]: 1 }; +})(); +console.log(aVal, bVal); From 27dc177f29f402ce5dc1b01086cc761ad4165b59 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 2 Dec 2020 18:11:45 -0800 Subject: [PATCH 2/6] Reuse temp variable scope for converted loop body --- src/compiler/transformers/es2015.ts | 2 +- .../asyncAwaitWithCapturedBlockScopeVar.js | 24 +++++++++--------- ...blockScopedBindingsInDownlevelGenerator.js | 6 ++--- .../reference/capturedLetConstInLoop10.js | 8 +++--- .../reference/capturedLetConstInLoop13.js | 8 +++--- .../reference/capturedLetConstInLoop9.js | 16 ++++++------ ...bclassWithExplicitNoArgumentConstructor.js | 2 ++ tests/baselines/reference/nestedLoops.js | 4 +-- .../newLexicalEnvironmentForConvertedLoop.js | 4 +-- .../reference/optionalChainingInLoop.js | 25 +++++++++++++++++++ .../optionalChainingInLoop.ts | 11 ++++++++ 11 files changed, 74 insertions(+), 36 deletions(-) create mode 100644 tests/baselines/reference/optionalChainingInLoop.js create mode 100644 tests/cases/conformance/expressions/optionalChaining/optionalChainingInLoop.ts diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index f7c20e74d67..60274fb6b45 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -3155,7 +3155,7 @@ namespace ts { const containsYield = (node.statement.transformFlags & TransformFlags.ContainsYield) !== 0; - let emitFlags: EmitFlags = 0; + let emitFlags: EmitFlags = EmitFlags.ReuseTempVariableScope; if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis; if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) emitFlags |= EmitFlags.AsyncFunctionBody; diff --git a/tests/baselines/reference/asyncAwaitWithCapturedBlockScopeVar.js b/tests/baselines/reference/asyncAwaitWithCapturedBlockScopeVar.js index 6d167a00089..259e6309449 100644 --- a/tests/baselines/reference/asyncAwaitWithCapturedBlockScopeVar.js +++ b/tests/baselines/reference/asyncAwaitWithCapturedBlockScopeVar.js @@ -44,11 +44,11 @@ function fn1() { case 0: ar = []; _loop_1 = function (i) { - return __generator(this, function (_a) { - switch (_a.label) { + return __generator(this, function (_b) { + switch (_b.label) { case 0: return [4 /*yield*/, 1]; case 1: - _a.sent(); + _b.sent(); ar.push(function () { return i; }); return [2 /*return*/]; } @@ -78,11 +78,11 @@ function fn2() { case 0: ar = []; _loop_2 = function (i) { - return __generator(this, function (_a) { - switch (_a.label) { + return __generator(this, function (_b) { + switch (_b.label) { case 0: return [4 /*yield*/, 1]; case 1: - _a.sent(); + _b.sent(); ar.push(function () { return i; }); return [2 /*return*/, "break"]; } @@ -114,11 +114,11 @@ function fn3() { case 0: ar = []; _loop_3 = function (i) { - return __generator(this, function (_a) { - switch (_a.label) { + return __generator(this, function (_b) { + switch (_b.label) { case 0: return [4 /*yield*/, 1]; case 1: - _a.sent(); + _b.sent(); ar.push(function () { return i; }); return [2 /*return*/, "continue"]; } @@ -148,11 +148,11 @@ function fn4() { case 0: ar = []; _loop_4 = function (i) { - return __generator(this, function (_a) { - switch (_a.label) { + return __generator(this, function (_b) { + switch (_b.label) { case 0: return [4 /*yield*/, 1]; case 1: - _a.sent(); + _b.sent(); ar.push(function () { return i; }); return [2 /*return*/, { value: 1 }]; } diff --git a/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js b/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js index 21b47adf6c7..eb59846f9e0 100644 --- a/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js +++ b/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js @@ -52,13 +52,13 @@ function a() { switch (_d.label) { case 0: _loop_1 = function (i) { - return __generator(this, function (_a) { - switch (_a.label) { + return __generator(this, function (_e) { + switch (_e.label) { case 0: (function () { return i; })(); return [4 /*yield*/, i]; case 1: - _a.sent(); + _e.sent(); return [2 /*return*/]; } }); diff --git a/tests/baselines/reference/capturedLetConstInLoop10.js b/tests/baselines/reference/capturedLetConstInLoop10.js index 304486e1724..d59d32f7d14 100644 --- a/tests/baselines/reference/capturedLetConstInLoop10.js +++ b/tests/baselines/reference/capturedLetConstInLoop10.js @@ -69,8 +69,8 @@ var A = /** @class */ (function () { var b = function () { return y; }; this_2.bar(b()); }; - for (var _i = 0, _a = [1]; _i < _a.length; _i++) { - var y = _a[_i]; + for (var _b = 0, _c = [1]; _b < _c.length; _b++) { + var y = _c[_b]; _loop_3(y); } this_2.bar(a()); @@ -89,8 +89,8 @@ var A = /** @class */ (function () { var b = function () { return y; }; this_3.bar(b()); }; - for (var _i = 0, _a = [1]; _i < _a.length; _i++) { - var y = _a[_i]; + for (var _b = 0, _c = [1]; _b < _c.length; _b++) { + var y = _c[_b]; _loop_5(y); } }; diff --git a/tests/baselines/reference/capturedLetConstInLoop13.js b/tests/baselines/reference/capturedLetConstInLoop13.js index 628faa10485..d0723c1f0f9 100644 --- a/tests/baselines/reference/capturedLetConstInLoop13.js +++ b/tests/baselines/reference/capturedLetConstInLoop13.js @@ -34,10 +34,10 @@ var Main = /** @class */ (function () { names[_i] = arguments[_i]; } var _loop_1 = function (name_1) { - var _a; - this_1.bar((_a = {}, - _a[name_1 + ".a"] = function () { _this.foo(name_1); }, - _a)); + var _b; + this_1.bar((_b = {}, + _b[name_1 + ".a"] = function () { _this.foo(name_1); }, + _b)); }; var this_1 = this; for (var _a = 0, names_1 = names; _a < names_1.length; _a++) { diff --git a/tests/baselines/reference/capturedLetConstInLoop9.js b/tests/baselines/reference/capturedLetConstInLoop9.js index 0795d509f9b..4f858a91a9c 100644 --- a/tests/baselines/reference/capturedLetConstInLoop9.js +++ b/tests/baselines/reference/capturedLetConstInLoop9.js @@ -178,16 +178,16 @@ for (var x = 0; x < 1; ++x) { } function foo() { var _loop_3 = function (a) { - var _a; + var _b; if (a === 1) { return "break"; } if (a === 2) { return "break-l0"; } - for (var _i = 0, _b = []; _i < _b.length; _i++) { - var b = _b[_i]; - _a = [{ x: 1, y: 2 }][0], x = _a.x, z = _a.y; + for (var _c = 0, _d = []; _c < _d.length; _c++) { + var b = _d[_c]; + _b = [{ x: 1, y: 2 }][0], x = _b.x, z = _b.y; if (b === 1) { break; } @@ -200,8 +200,8 @@ function foo() { return { value: 50 }; } var _loop_4 = function (b) { - var _a; - _a = [{ x1: 1, y: arguments_1.length }][0], x1 = _a.x1, z1 = _a.y; + var _g; + _g = [{ x1: 1, y: arguments_1.length }][0], x1 = _g.x1, z1 = _g.y; if (b === 1) { return "break"; } @@ -211,8 +211,8 @@ function foo() { (function () { return b; }); return { value: 100 }; }; - for (var _c = 0, _d = []; _c < _d.length; _c++) { - var b = _d[_c]; + for (var _e = 0, _f = []; _e < _f.length; _e++) { + var b = _f[_e]; var state_2 = _loop_4(b); if (typeof state_2 === "object") return state_2; diff --git a/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js b/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js index 42cafa5e355..8abe7764586 100644 --- a/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js +++ b/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js @@ -23,6 +23,8 @@ var __extends = (this && this.__extends) || (function () { return extendStatics(d, b); }; return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); diff --git a/tests/baselines/reference/nestedLoops.js b/tests/baselines/reference/nestedLoops.js index f1d1f490bd6..1c7d5383cea 100644 --- a/tests/baselines/reference/nestedLoops.js +++ b/tests/baselines/reference/nestedLoops.js @@ -31,8 +31,8 @@ var Test = /** @class */ (function () { var x = outer + inner + newValue; }); }; - for (var _i = 0, innerArray_1 = innerArray; _i < innerArray_1.length; _i++) { - var inner = innerArray_1[_i]; + for (var _a = 0, innerArray_1 = innerArray; _a < innerArray_1.length; _a++) { + var inner = innerArray_1[_a]; _loop_2(inner); } }; diff --git a/tests/baselines/reference/newLexicalEnvironmentForConvertedLoop.js b/tests/baselines/reference/newLexicalEnvironmentForConvertedLoop.js index b6263c1d34a..ee1c439b932 100644 --- a/tests/baselines/reference/newLexicalEnvironmentForConvertedLoop.js +++ b/tests/baselines/reference/newLexicalEnvironmentForConvertedLoop.js @@ -18,10 +18,10 @@ function baz(x) { } function foo(set) { var _loop_1 = function (value, i) { - var _a; + var _c; var bar = []; (function () { return bar; }); - (_a = set.values).push.apply(_a, []); + (_c = set.values).push.apply(_c, []); }; for (var _i = 0, _a = baz(set.values); _i < _a.length; _i++) { var _b = _a[_i], value = _b[0], i = _b[1]; diff --git a/tests/baselines/reference/optionalChainingInLoop.js b/tests/baselines/reference/optionalChainingInLoop.js new file mode 100644 index 00000000000..8ca2676d0ad --- /dev/null +++ b/tests/baselines/reference/optionalChainingInLoop.js @@ -0,0 +1,25 @@ +//// [optionalChainingInLoop.ts] +// https://github.com/microsoft/TypeScript/issues/40643 +const list: any[] = [] +for (const comp of list) { + comp.sp.y = comp.sp.r.find((k: any) => k.c == (comp.xp ? '1' : '0')) + for (const item of comp.c) { + item.v = !!item.t?.length + } +} + +//// [optionalChainingInLoop.js] +var _a; +// https://github.com/microsoft/TypeScript/issues/40643 +var list = []; +var _loop_1 = function (comp) { + comp.sp.y = comp.sp.r.find(function (k) { return k.c == (comp.xp ? '1' : '0'); }); + for (var _b = 0, _c = comp.c; _b < _c.length; _b++) { + var item = _c[_b]; + item.v = !!((_a = item.t) === null || _a === void 0 ? void 0 : _a.length); + } +}; +for (var _i = 0, list_1 = list; _i < list_1.length; _i++) { + var comp = list_1[_i]; + _loop_1(comp); +} diff --git a/tests/cases/conformance/expressions/optionalChaining/optionalChainingInLoop.ts b/tests/cases/conformance/expressions/optionalChaining/optionalChainingInLoop.ts new file mode 100644 index 00000000000..d52f2a2f29f --- /dev/null +++ b/tests/cases/conformance/expressions/optionalChaining/optionalChainingInLoop.ts @@ -0,0 +1,11 @@ +// @target: es5 +// @lib: es2015 +// @noTypesAndSymbols: true +// https://github.com/microsoft/TypeScript/issues/40643 +const list: any[] = [] +for (const comp of list) { + comp.sp.y = comp.sp.r.find((k: any) => k.c == (comp.xp ? '1' : '0')) + for (const item of comp.c) { + item.v = !!item.t?.length + } +} \ No newline at end of file From add10ec61fc122acdd1263d35590075503767fef Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Thu, 3 Dec 2020 06:21:40 +0000 Subject: [PATCH 3/6] Update package-lock.json --- package-lock.json | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9028570b840..8dc53dffe5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -280,15 +280,15 @@ } }, "@octokit/core": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.2.tgz", - "integrity": "sha512-cZEP6dC8xpepbAqtdS1GgX88omLer8VQegw5BpQ5fbSrkxgY9Y9K7ratu8ezAd9bD0GVOR1GVWiRzYdxiprU1w==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.3.tgz", + "integrity": "sha512-0ANaYovDuwXW1ZHk9jBUDcZWHqdMlhDV8Z0oHVRk4Sq0QCmQOprvnIjIQSGkXgKlhdTpPo0wwvvMnhqiXeR7DA==", "dev": true, "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/graphql": "^4.3.1", - "@octokit/request": "^5.4.0", - "@octokit/types": "^6.0.0", + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.4.12", + "@octokit/types": "^6.0.3", "before-after-hook": "^2.1.0", "universal-user-agent": "^6.0.0" } @@ -322,9 +322,9 @@ "dev": true }, "@octokit/plugin-paginate-rest": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.6.1.tgz", - "integrity": "sha512-DprxhI/8Qf/x9Svy89RUh3szyiLwgHL67S5kNmm5B4AjcWrPpMzB25fMCZeIIaXT463Fdn6fc1Hy6kK7/Hd90Q==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.6.2.tgz", + "integrity": "sha512-3Dy7/YZAwdOaRpGQoNHPeT0VU1fYLpIUdPyvR37IyFLgd6XSij4j9V/xN/+eSjF2KKvmfIulEh9LF1tRPjIiDA==", "dev": true, "requires": { "@octokit/types": "^6.0.1" @@ -347,14 +347,14 @@ } }, "@octokit/request": { - "version": "5.4.11", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.11.tgz", - "integrity": "sha512-vskebNjuz4oTdPIv+9cQjHvjk8vjrMv2fOmSo6zr7IIaFHeVsJlG/C07MXiSS/+g/qU1GHjkPG1XW3faz57EoQ==", + "version": "5.4.12", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.12.tgz", + "integrity": "sha512-MvWYdxengUWTGFpfpefBBpVmmEYfkwMoxonIB3sUGp5rhdgwjXL1ejo6JbgzG/QD9B/NYt/9cJX1pxXeSIUCkg==", "dev": true, "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.0.0", - "@octokit/types": "^6.0.0", + "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", "is-plain-object": "^5.0.0", "node-fetch": "^2.6.1", @@ -394,9 +394,9 @@ } }, "@octokit/types": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.0.1.tgz", - "integrity": "sha512-H/DnTKC+U09en2GFLH/MfAPNDaYb1isieD4Hx4NLpEt/I1PgtZP/8a+Ehc/j9GHuVF/UvGtOVD8AF9XXvws53w==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.0.3.tgz", + "integrity": "sha512-6y0Emzp+uPpdC5QLzUY1YRklvqiZBMTOz2ByhXdmTFlc3lNv8Mi28dX1U1b4scNtFMUa3tkpjofNFJ5NqMJaZw==", "dev": true, "requires": { "@octokit/openapi-types": "^1.2.0", @@ -4486,9 +4486,9 @@ "dev": true }, "is-generator-function": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", - "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz", + "integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==", "dev": true }, "is-glob": { From 8d952cb43e8fe163d5ae2afb857d938241402ff2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 3 Dec 2020 08:59:14 -0800 Subject: [PATCH 4/6] Fix insufficiently merged baselines (#41803) --- .../jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js b/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js index 42cafa5e355..8abe7764586 100644 --- a/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js +++ b/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js @@ -23,6 +23,8 @@ var __extends = (this && this.__extends) || (function () { return extendStatics(d, b); }; return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); From 69bc3f3b0c9c553f94ff53bdb46864ffafa833c6 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 3 Dec 2020 13:27:15 -0800 Subject: [PATCH 5/6] Allow type-only imports on ImportEqualsDeclarations (#41573) * Allow type-only ImportEqualsDeclarations * Suppress CJS-in-ESM error when type-only * Add grammar error on import type in import alias * Update API baselines * Fix importsNotUsedAsValues with ImportEqualsDeclarations * Make bad error talk words more good for Daniel. Fixes #41603 * One more error message baseline update * Update transformer and emitter --- src/compiler/checker.ts | 42 ++++++++++---- src/compiler/diagnosticMessages.json | 10 ++-- src/compiler/emitter.ts | 4 ++ src/compiler/factory/nodeFactory.ts | 8 ++- src/compiler/parser.ts | 5 +- src/compiler/transformers/declarations.ts | 1 + src/compiler/transformers/ts.ts | 5 ++ src/compiler/types.ts | 6 +- src/compiler/utilitiesPublic.ts | 3 +- src/compiler/visitorPublic.ts | 5 +- .../codefixes/convertToTypeOnlyImport.ts | 2 +- .../codefixes/fixInvalidImportSyntax.ts | 1 + src/services/codefixes/importFixes.ts | 1 + src/services/codefixes/requireInTs.ts | 2 +- src/services/refactors/moveToNewFile.ts | 4 +- .../reference/api/tsserverlibrary.d.ts | 11 ++-- tests/baselines/reference/api/typescript.d.ts | 11 ++-- .../baselines/reference/cjsImportInES2015.js | 14 +++++ .../reference/cjsImportInES2015.symbols | 17 ++++++ .../reference/cjsImportInES2015.types | 16 ++++++ .../reference/grammarErrors.errors.txt | 9 +++ tests/baselines/reference/grammarErrors.js | 16 ++++++ .../importEqualsDeclaration.errors.txt | 23 ++++++++ .../reference/importEqualsDeclaration.js | 57 +++++++++++++++++++ .../importEqualsDeclarationError.errors.txt | 17 ------ .../importsNotUsedAsValues_error.errors.txt | 40 ++++++++++--- .../reference/importsNotUsedAsValues_error.js | 47 ++++++++++++++- .../importsNotUsedAsValues_error.symbols | 45 +++++++++++++++ .../importsNotUsedAsValues_error.types | 46 +++++++++++++++ ...tes-diagnostics-and-emit-for-decorators.js | 4 +- ...mit-when-importsNotUsedAsValues-changes.js | 2 +- .../typeOnly/cjsImportInES2015.ts | 10 ++++ .../externalModules/typeOnly/grammarErrors.ts | 6 ++ .../typeOnly/importEqualsDeclaration.ts | 19 +++++++ .../typeOnly/importEqualsDeclarationError.ts | 14 ----- .../typeOnly/importsNotUsedAsValues_error.ts | 25 +++++++- 36 files changed, 463 insertions(+), 85 deletions(-) create mode 100644 tests/baselines/reference/cjsImportInES2015.js create mode 100644 tests/baselines/reference/cjsImportInES2015.symbols create mode 100644 tests/baselines/reference/cjsImportInES2015.types create mode 100644 tests/baselines/reference/importEqualsDeclaration.errors.txt create mode 100644 tests/baselines/reference/importEqualsDeclaration.js delete mode 100644 tests/baselines/reference/importEqualsDeclarationError.errors.txt create mode 100644 tests/cases/conformance/externalModules/typeOnly/cjsImportInES2015.ts create mode 100644 tests/cases/conformance/externalModules/typeOnly/importEqualsDeclaration.ts delete mode 100644 tests/cases/conformance/externalModules/typeOnly/importEqualsDeclarationError.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9d1241098ce..ea35af4c80d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2482,7 +2482,7 @@ namespace ts { const immediate = resolveExternalModuleName( node, getExternalModuleRequireArgument(node) || getExternalModuleImportEqualsDeclarationExpression(node)); - const resolved = resolveExternalModuleSymbol(immediate); + const resolved = resolveExternalModuleSymbol(immediate); markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); return resolved; } @@ -2492,7 +2492,7 @@ namespace ts { } function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) { - if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false)) { + if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) { const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfNode(node))!; const isExport = typeOnlyDeclarationIsExport(typeOnlyDeclaration); const message = isExport @@ -6841,6 +6841,7 @@ namespace ts { addResult(factory.createImportEqualsDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, + /*isTypeOnly*/ false, uniqueName, factory.createExternalModuleReference(factory.createStringLiteral(specifier)) ), ModifierFlags.None); @@ -6848,6 +6849,7 @@ namespace ts { addResult(factory.createImportEqualsDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, + /*isTypeOnly*/ false, factory.createIdentifier(localName), factory.createQualifiedName(uniqueName, initializer.name as Identifier), ), modifierFlags); @@ -6867,6 +6869,7 @@ namespace ts { addResult(factory.createImportEqualsDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, + /*isTypeOnly*/ false, factory.createIdentifier(localName), isLocalImport ? symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) @@ -7024,6 +7027,7 @@ namespace ts { addResult(factory.createImportEqualsDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, + /*isTypeOnly*/ false, factory.createIdentifier(varName), symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) ), ModifierFlags.None); @@ -36459,9 +36463,12 @@ namespace ts { checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0); } } + if (node.isTypeOnly) { + grammarErrorOnNode(node, Diagnostics.An_import_alias_cannot_use_import_type); + } } else { - if (moduleKind >= ModuleKind.ES2015 && !(node.flags & NodeFlags.Ambient)) { + if (moduleKind >= ModuleKind.ES2015 && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) { // Import equals declaration is deprecated in es6 or above grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead); } @@ -36552,19 +36559,30 @@ namespace ts { }); } + function canConvertImportDeclarationToTypeOnly(statement: Statement) { + return isImportDeclaration(statement) && + statement.importClause && + !statement.importClause.isTypeOnly && + importClauseContainsReferencedImport(statement.importClause) && + !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) && + !importClauseContainsConstEnumUsedAsValue(statement.importClause); + } + + function canConvertImportEqualsDeclarationToTypeOnly(statement: Statement) { + return isImportEqualsDeclaration(statement) && + isExternalModuleReference(statement.moduleReference) && + !statement.isTypeOnly && + getSymbolOfNode(statement).isReferenced && + !isReferencedAliasDeclaration(statement, /*checkChildren*/ false) && + !getSymbolLinks(getSymbolOfNode(statement)).constEnumReferenced; + } + function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) { for (const statement of sourceFile.statements) { - if ( - isImportDeclaration(statement) && - statement.importClause && - !statement.importClause.isTypeOnly && - importClauseContainsReferencedImport(statement.importClause) && - !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) && - !importClauseContainsConstEnumUsedAsValue(statement.importClause) - ) { + if (canConvertImportDeclarationToTypeOnly(statement) || canConvertImportEqualsDeclarationToTypeOnly(statement)) { error( statement, - Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_the_importsNotUsedAsValues_is_set_to_error); + Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error); } } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4cb607631f5..cabacfaa012 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1112,11 +1112,7 @@ "category": "Message", "code": 1369 }, - "Only ECMAScript imports may use 'import type'.": { - "category": "Error", - "code": 1370 - }, - "This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.": { + "This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.": { "category": "Error", "code": 1371 }, @@ -1196,6 +1192,10 @@ "category": "Error", "code": 1391 }, + "An import alias cannot use 'import type'": { + "category": "Error", + "code": 1392 + }, "The types of '{0}' are incompatible between these types.": { "category": "Error", "code": 2200 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 83a0a7ed9d8..7f77f70880a 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3155,6 +3155,10 @@ namespace ts { emitModifiers(node, node.modifiers); emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node); writeSpace(); + if (node.isTypeOnly) { + emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node); + writeSpace(); + } emit(node.name); writeSpace(); emitTokenWithComment(SyntaxKind.EqualsToken, node.name.end, writePunctuation, node); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index aadd082a466..176c9154dcd 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -3776,6 +3776,7 @@ namespace ts { function createImportEqualsDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference ) { @@ -3785,6 +3786,7 @@ namespace ts { modifiers, name ); + node.isTypeOnly = isTypeOnly; node.moduleReference = moduleReference; node.transformFlags |= propagateChildFlags(node.moduleReference); if (!isExternalModuleReference(node.moduleReference)) node.transformFlags |= TransformFlags.ContainsTypeScript; @@ -3797,14 +3799,16 @@ namespace ts { node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference ) { return node.decorators !== decorators || node.modifiers !== modifiers + || node.isTypeOnly !== isTypeOnly || node.name !== name || node.moduleReference !== moduleReference - ? update(createImportEqualsDeclaration(decorators, modifiers, name, moduleReference), node) + ? update(createImportEqualsDeclaration(decorators, modifiers, isTypeOnly, name, moduleReference), node) : node; } @@ -5798,7 +5802,7 @@ namespace ts { isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.type) : isEnumDeclaration(node) ? updateEnumDeclaration(node, node.decorators, modifiers, node.name, node.members) : isModuleDeclaration(node) ? updateModuleDeclaration(node, node.decorators, modifiers, node.name, node.body) : - isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, node.decorators, modifiers, node.name, node.moduleReference) : + isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, node.decorators, modifiers, node.isTypeOnly, node.name, node.moduleReference) : isImportDeclaration(node) ? updateImportDeclaration(node, node.decorators, modifiers, node.importClause, node.moduleSpecifier) : isExportAssignment(node) ? updateExportAssignment(node, node.decorators, modifiers, node.expression) : isExportDeclaration(node) ? updateExportDeclaration(node, node.decorators, modifiers, node.isTypeOnly, node.exportClause, node.moduleSpecifier) : diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ac810e305af..5dcfb5ee075 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6929,11 +6929,8 @@ namespace ts { parseExpected(SyntaxKind.EqualsToken); const moduleReference = parseModuleReference(); parseSemicolon(); - const node = factory.createImportEqualsDeclaration(decorators, modifiers, identifier, moduleReference); + const node = factory.createImportEqualsDeclaration(decorators, modifiers, isTypeOnly, identifier, moduleReference); const finished = withJSDoc(finishNode(node, pos), hasJSDoc); - if (isTypeOnly) { - parseErrorAtRange(finished, Diagnostics.Only_ECMAScript_imports_may_use_import_type); - } return finished; } diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index ccb9dae665e..1fc500d2da8 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -681,6 +681,7 @@ namespace ts { decl, /*decorators*/ undefined, decl.modifiers, + decl.isTypeOnly, decl.name, factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier)) ); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 98fff3625ab..9cc9c1c3fc9 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2973,6 +2973,11 @@ namespace ts { * @param node The import equals declaration node. */ function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { + // Always elide type-only imports + if (node.isTypeOnly) { + return undefined; + } + if (isExternalModuleImportEqualsDeclaration(node)) { const isReferenced = resolver.isReferencedAliasDeclaration(node); // If the alias is unreferenced but we want to keep the import, replace with 'import "mod"'. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7c9038ed3ba..34245a5e404 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2925,6 +2925,7 @@ namespace ts { readonly kind: SyntaxKind.ImportEqualsDeclaration; readonly parent: SourceFile | ModuleBlock; readonly name: Identifier; + readonly isTypeOnly: boolean; // 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external // module reference. @@ -3037,6 +3038,7 @@ namespace ts { export type TypeOnlyCompatibleAliasDeclaration = | ImportClause + | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier ; @@ -7001,8 +7003,8 @@ namespace ts { updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock; createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration; updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration; - createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; - updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration; updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration; createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause; diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 0f702eba480..6722e7ad5be 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1107,7 +1107,8 @@ namespace ts { case SyntaxKind.NamespaceImport: return (node as NamespaceImport).parent.isTypeOnly; case SyntaxKind.ImportClause: - return (node as ImportClause).isTypeOnly; + case SyntaxKind.ImportEqualsDeclaration: + return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly; default: return false; } diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 8a06e110552..ad6e45f4011 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -937,6 +937,7 @@ namespace ts { return factory.updateImportEqualsDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), + (node).isTypeOnly, nodeVisitor((node).name, visitor, isIdentifier), nodeVisitor((node).moduleReference, visitor, isModuleReference)); @@ -949,7 +950,7 @@ namespace ts { case SyntaxKind.ImportClause: return factory.updateImportClause(node, - (node as ImportClause).isTypeOnly, + (node).isTypeOnly, nodeVisitor((node).name, visitor, isIdentifier), nodeVisitor((node).namedBindings, visitor, isNamedImportBindings)); @@ -980,7 +981,7 @@ namespace ts { return factory.updateExportDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), - (node as ExportDeclaration).isTypeOnly, + (node).isTypeOnly, nodeVisitor((node).exportClause, visitor, isNamedExportBindings), nodeVisitor((node).moduleSpecifier, visitor, isExpression)); diff --git a/src/services/codefixes/convertToTypeOnlyImport.ts b/src/services/codefixes/convertToTypeOnlyImport.ts index 7079ee8d2ba..daa163250df 100644 --- a/src/services/codefixes/convertToTypeOnlyImport.ts +++ b/src/services/codefixes/convertToTypeOnlyImport.ts @@ -1,6 +1,6 @@ /* @internal */ namespace ts.codefix { - const errorCodes = [Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_the_importsNotUsedAsValues_is_set_to_error.code]; + const errorCodes = [Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error.code]; const fixId = "convertToTypeOnlyImport"; registerCodeFix({ errorCodes, diff --git a/src/services/codefixes/fixInvalidImportSyntax.ts b/src/services/codefixes/fixInvalidImportSyntax.ts index acc033df36f..9728cc032f2 100644 --- a/src/services/codefixes/fixInvalidImportSyntax.ts +++ b/src/services/codefixes/fixInvalidImportSyntax.ts @@ -16,6 +16,7 @@ namespace ts.codefix { variations.push(createAction(context, sourceFile, node, factory.createImportEqualsDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, + /*isTypeOnly*/ false, namespace.name, factory.createExternalModuleReference(node.moduleSpecifier) ))); diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 407903390ef..4ba390cca97 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -795,6 +795,7 @@ namespace ts.codefix { ? factory.createImportEqualsDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, + typeOnly, factory.createIdentifier(namespaceLikeImport.name), factory.createExternalModuleReference(quotedModuleSpecifier)) : factory.createImportDeclaration( diff --git a/src/services/codefixes/requireInTs.ts b/src/services/codefixes/requireInTs.ts index f990f5cadb2..c1ee73013fa 100644 --- a/src/services/codefixes/requireInTs.ts +++ b/src/services/codefixes/requireInTs.ts @@ -24,7 +24,7 @@ namespace ts.codefix { function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info) { const { allowSyntheticDefaults, defaultImportName, namedImports, statement, required } = info; changes.replaceNode(sourceFile, statement, defaultImportName && !allowSyntheticDefaults - ? factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, defaultImportName, factory.createExternalModuleReference(required)) + ? factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(required)) : factory.createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required)); } diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index 8c3f4504925..bf5609620e6 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -245,7 +245,7 @@ namespace ts.refactor { factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(newNamespaceId)), newModuleString); case SyntaxKind.ImportEqualsDeclaration: - return factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, newNamespaceId, factory.createExternalModuleReference(newModuleString)); + return factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*isTypeOnly*/ false, newNamespaceId, factory.createExternalModuleReference(newModuleString)); case SyntaxKind.VariableDeclaration: return factory.createVariableDeclaration(newNamespaceId, /*exclamationToken*/ undefined, /*type*/ undefined, createRequireCall(newModuleString)); default: @@ -782,7 +782,7 @@ namespace ts.refactor { case SyntaxKind.InterfaceDeclaration: return factory.updateInterfaceDeclaration(d, d.decorators, modifiers, d.name, d.typeParameters, d.heritageClauses, d.members); case SyntaxKind.ImportEqualsDeclaration: - return factory.updateImportEqualsDeclaration(d, d.decorators, modifiers, d.name, d.moduleReference); + return factory.updateImportEqualsDeclaration(d, d.decorators, modifiers, d.isTypeOnly, d.name, d.moduleReference); case SyntaxKind.ExpressionStatement: return Debug.fail(); // Shouldn't try to add 'export' keyword to `exports.x = ...` default: diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index c269e0f0b0b..ccc5d1fa1fc 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1598,6 +1598,7 @@ declare namespace ts { readonly kind: SyntaxKind.ImportEqualsDeclaration; readonly parent: SourceFile | ModuleBlock; readonly name: Identifier; + readonly isTypeOnly: boolean; readonly moduleReference: ModuleReference; } export interface ExternalModuleReference extends Node { @@ -1668,7 +1669,7 @@ declare namespace ts { readonly name: Identifier; } export type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier; - export type TypeOnlyCompatibleAliasDeclaration = ImportClause | NamespaceImport | ImportOrExportSpecifier; + export type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier; /** * This is either an `export =` or an `export default` declaration. * Unless `isExportEquals` is set, this node was parsed as an `export default`. @@ -3410,8 +3411,8 @@ declare namespace ts { updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock; createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration; updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration; - createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; - updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration; updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration; createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause; @@ -10505,9 +10506,9 @@ declare namespace ts { /** @deprecated Use `factory.updateNamespaceExportDeclaration` or the factory supplied by your transformation context instead. */ const updateNamespaceExportDeclaration: (node: NamespaceExportDeclaration, name: Identifier) => NamespaceExportDeclaration; /** @deprecated Use `factory.createImportEqualsDeclaration` or the factory supplied by your transformation context instead. */ - const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; + const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; /** @deprecated Use `factory.updateImportEqualsDeclaration` or the factory supplied by your transformation context instead. */ - const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; + const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; /** @deprecated Use `factory.createImportDeclaration` or the factory supplied by your transformation context instead. */ const createImportDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression) => ImportDeclaration; /** @deprecated Use `factory.updateImportDeclaration` or the factory supplied by your transformation context instead. */ diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index f985d34fdd3..440cebf6b0d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1598,6 +1598,7 @@ declare namespace ts { readonly kind: SyntaxKind.ImportEqualsDeclaration; readonly parent: SourceFile | ModuleBlock; readonly name: Identifier; + readonly isTypeOnly: boolean; readonly moduleReference: ModuleReference; } export interface ExternalModuleReference extends Node { @@ -1668,7 +1669,7 @@ declare namespace ts { readonly name: Identifier; } export type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier; - export type TypeOnlyCompatibleAliasDeclaration = ImportClause | NamespaceImport | ImportOrExportSpecifier; + export type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier; /** * This is either an `export =` or an `export default` declaration. * Unless `isExportEquals` is set, this node was parsed as an `export default`. @@ -3410,8 +3411,8 @@ declare namespace ts { updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock; createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration; updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration; - createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; - updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration; updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration; createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause; @@ -6865,9 +6866,9 @@ declare namespace ts { /** @deprecated Use `factory.updateNamespaceExportDeclaration` or the factory supplied by your transformation context instead. */ const updateNamespaceExportDeclaration: (node: NamespaceExportDeclaration, name: Identifier) => NamespaceExportDeclaration; /** @deprecated Use `factory.createImportEqualsDeclaration` or the factory supplied by your transformation context instead. */ - const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; + const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; /** @deprecated Use `factory.updateImportEqualsDeclaration` or the factory supplied by your transformation context instead. */ - const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; + const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration; /** @deprecated Use `factory.createImportDeclaration` or the factory supplied by your transformation context instead. */ const createImportDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression) => ImportDeclaration; /** @deprecated Use `factory.updateImportDeclaration` or the factory supplied by your transformation context instead. */ diff --git a/tests/baselines/reference/cjsImportInES2015.js b/tests/baselines/reference/cjsImportInES2015.js new file mode 100644 index 00000000000..25daeab406a --- /dev/null +++ b/tests/baselines/reference/cjsImportInES2015.js @@ -0,0 +1,14 @@ +//// [tests/cases/conformance/externalModules/typeOnly/cjsImportInES2015.ts] //// + +//// [index.d.ts] +declare class SpecialError extends Error {} +export = SpecialError; + +//// [index.ts] +import type SpecialError = require("cjs-dep"); +function handleError(err: SpecialError) {} + + +//// [index.js] +function handleError(err) { } +export {}; diff --git a/tests/baselines/reference/cjsImportInES2015.symbols b/tests/baselines/reference/cjsImportInES2015.symbols new file mode 100644 index 00000000000..8620d585bbd --- /dev/null +++ b/tests/baselines/reference/cjsImportInES2015.symbols @@ -0,0 +1,17 @@ +=== /project/index.ts === +import type SpecialError = require("cjs-dep"); +>SpecialError : Symbol(SpecialError, Decl(index.ts, 0, 0)) + +function handleError(err: SpecialError) {} +>handleError : Symbol(handleError, Decl(index.ts, 0, 46)) +>err : Symbol(err, Decl(index.ts, 1, 21)) +>SpecialError : Symbol(SpecialError, Decl(index.ts, 0, 0)) + +=== /project/node_modules/cjs-dep/index.d.ts === +declare class SpecialError extends Error {} +>SpecialError : Symbol(SpecialError, Decl(index.d.ts, 0, 0)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +export = SpecialError; +>SpecialError : Symbol(SpecialError, Decl(index.d.ts, 0, 0)) + diff --git a/tests/baselines/reference/cjsImportInES2015.types b/tests/baselines/reference/cjsImportInES2015.types new file mode 100644 index 00000000000..e4a5a814657 --- /dev/null +++ b/tests/baselines/reference/cjsImportInES2015.types @@ -0,0 +1,16 @@ +=== /project/index.ts === +import type SpecialError = require("cjs-dep"); +>SpecialError : typeof SpecialError + +function handleError(err: SpecialError) {} +>handleError : (err: SpecialError) => void +>err : SpecialError + +=== /project/node_modules/cjs-dep/index.d.ts === +declare class SpecialError extends Error {} +>SpecialError : SpecialError +>Error : Error + +export = SpecialError; +>SpecialError : SpecialError + diff --git a/tests/baselines/reference/grammarErrors.errors.txt b/tests/baselines/reference/grammarErrors.errors.txt index ad9d7c9f859..bf1009be1c8 100644 --- a/tests/baselines/reference/grammarErrors.errors.txt +++ b/tests/baselines/reference/grammarErrors.errors.txt @@ -4,6 +4,7 @@ error TS5056: Cannot write file '/a.js' because it would be overwritten by multi /a.js(1,1): error TS8006: 'import type' declarations can only be used in TypeScript files. /a.js(2,1): error TS8006: 'export type' declarations can only be used in TypeScript files. /b.ts(1,8): error TS1363: A type-only import can specify a default import or named bindings, but not both. +/c.ts(4,1): error TS1392: An import alias cannot use 'import type' !!! error TS5055: Cannot write file '/a.js' because it would overwrite input file. @@ -26,4 +27,12 @@ error TS5056: Cannot write file '/a.js' because it would be overwritten by multi export type { A }; ~~~~~~~~~~~~~~~~~~ !!! error TS8006: 'export type' declarations can only be used in TypeScript files. + +==== /c.ts (1 errors) ==== + namespace ns { + export class Foo {} + } + import type Foo = ns.Foo; + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1392: An import alias cannot use 'import type' \ No newline at end of file diff --git a/tests/baselines/reference/grammarErrors.js b/tests/baselines/reference/grammarErrors.js index bb1e4e1d1ec..16acd74514b 100644 --- a/tests/baselines/reference/grammarErrors.js +++ b/tests/baselines/reference/grammarErrors.js @@ -12,7 +12,23 @@ import type A, { B, C } from './a'; import type A from './a'; export type { A }; +//// [c.ts] +namespace ns { + export class Foo {} +} +import type Foo = ns.Foo; + //// [b.js] "use strict"; exports.__esModule = true; +//// [c.js] +var ns; +(function (ns) { + var Foo = /** @class */ (function () { + function Foo() { + } + return Foo; + }()); + ns.Foo = Foo; +})(ns || (ns = {})); diff --git a/tests/baselines/reference/importEqualsDeclaration.errors.txt b/tests/baselines/reference/importEqualsDeclaration.errors.txt new file mode 100644 index 00000000000..3e338465ded --- /dev/null +++ b/tests/baselines/reference/importEqualsDeclaration.errors.txt @@ -0,0 +1,23 @@ +/c.ts(4,1): error TS1361: 'A' cannot be used as a value because it was imported using 'import type'. + + +==== /c.ts (1 errors) ==== + import type A = require('./a'); // Ok + import type = require('./b'); // Ok + + A.prototype; // Error + ~ +!!! error TS1361: 'A' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 /c.ts:1:1: 'A' was imported here. + const a: A = { a: 'a' }; // Ok + void type; // Ok + export declare const AConstructor: typeof A; // Ok + +==== /a.ts (0 errors) ==== + class A { a!: string } + export = A; + +==== /b.ts (0 errors) ==== + class SomeClass {} + export = SomeClass; + \ No newline at end of file diff --git a/tests/baselines/reference/importEqualsDeclaration.js b/tests/baselines/reference/importEqualsDeclaration.js new file mode 100644 index 00000000000..56ee60e4712 --- /dev/null +++ b/tests/baselines/reference/importEqualsDeclaration.js @@ -0,0 +1,57 @@ +//// [tests/cases/conformance/externalModules/typeOnly/importEqualsDeclaration.ts] //// + +//// [a.ts] +class A { a!: string } +export = A; + +//// [b.ts] +class SomeClass {} +export = SomeClass; + +//// [c.ts] +import type A = require('./a'); // Ok +import type = require('./b'); // Ok + +A.prototype; // Error +const a: A = { a: 'a' }; // Ok +void type; // Ok +export declare const AConstructor: typeof A; // Ok + + +//// [a.js] +"use strict"; +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +module.exports = A; +//// [b.js] +"use strict"; +var SomeClass = /** @class */ (function () { + function SomeClass() { + } + return SomeClass; +}()); +module.exports = SomeClass; +//// [c.js] +"use strict"; +exports.__esModule = true; +var type = require("./b"); // Ok +A.prototype; // Error +var a = { a: 'a' }; // Ok +void type; // Ok + + +//// [a.d.ts] +declare class A { + a: string; +} +export = A; +//// [b.d.ts] +declare class SomeClass { +} +export = SomeClass; +//// [c.d.ts] +import type A = require('./a'); +export declare const AConstructor: typeof A; diff --git a/tests/baselines/reference/importEqualsDeclarationError.errors.txt b/tests/baselines/reference/importEqualsDeclarationError.errors.txt deleted file mode 100644 index 1d3f606b3e0..00000000000 --- a/tests/baselines/reference/importEqualsDeclarationError.errors.txt +++ /dev/null @@ -1,17 +0,0 @@ -/c.ts(1,1): error TS1370: Only ECMAScript imports may use 'import type'. - - -==== /c.ts (1 errors) ==== - import type T = require('./a'); // Error - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1370: Only ECMAScript imports may use 'import type'. - import type = require('./b'); // Ok - -==== /a.ts (0 errors) ==== - type T = {}; - export = T; - -==== /b.ts (0 errors) ==== - class SomeClass {} - export = SomeClass; - \ No newline at end of file diff --git a/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt b/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt index 8fd94533617..7bc4014bc55 100644 --- a/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt +++ b/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt @@ -1,7 +1,8 @@ -/b.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. -/c.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +/b.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. +/c.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. /e.ts(1,1): error TS6192: All imports in import declaration are unused. -/g.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +/g.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. +/i.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. ==== /a.ts (0 errors) ==== @@ -13,7 +14,7 @@ ==== /b.ts (1 errors) ==== import { A, B } from './a'; // Error ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. let a: A; let b: B; console.log(a, b); @@ -21,7 +22,7 @@ ==== /c.ts (1 errors) ==== import Default, * as named from './a'; // Error ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. let a: Default; let b: named.B; console.log(a, b); @@ -48,7 +49,32 @@ ==== /g.ts (1 errors) ==== import { C } from './a'; ~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. let c: C; let d: C.Two; - console.log(c, d); \ No newline at end of file + console.log(c, d); + +==== /h.ts (0 errors) ==== + class H {} + export = H; + +==== /i.ts (1 errors) ==== + import H = require('./h'); // Error + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. + let h: H = {}; + console.log(h); + +==== /j.ts (0 errors) ==== + import H = require('./h'); // noUnusedLocals error only + +==== /k.ts (0 errors) ==== + const enum K { One, Two } + export = K; + +==== /l.ts (0 errors) ==== + import K = require('./k'); + K.One; + +==== /j.ts (0 errors) ==== + // Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207 \ No newline at end of file diff --git a/tests/baselines/reference/importsNotUsedAsValues_error.js b/tests/baselines/reference/importsNotUsedAsValues_error.js index 19c43625896..e7ccbd7b21c 100644 --- a/tests/baselines/reference/importsNotUsedAsValues_error.js +++ b/tests/baselines/reference/importsNotUsedAsValues_error.js @@ -39,7 +39,30 @@ console.log(c, d); import { C } from './a'; let c: C; let d: C.Two; -console.log(c, d); +console.log(c, d); + +//// [h.ts] +class H {} +export = H; + +//// [i.ts] +import H = require('./h'); // Error +let h: H = {}; +console.log(h); + +//// [j.ts] +import H = require('./h'); // noUnusedLocals error only + +//// [k.ts] +const enum K { One, Two } +export = K; + +//// [l.ts] +import K = require('./k'); +K.One; + +//// [j.ts] +// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207 //// [a.js] "use strict"; @@ -97,3 +120,25 @@ require("./a"); var c; var d; console.log(c, d); +//// [h.js] +"use strict"; +var H = /** @class */ (function () { + function H() { + } + return H; +}()); +module.exports = H; +//// [i.js] +"use strict"; +exports.__esModule = true; +var h = {}; +console.log(h); +//// [j.js] +// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207 +//// [k.js] +"use strict"; +exports.__esModule = true; +//// [l.js] +"use strict"; +exports.__esModule = true; +0 /* One */; diff --git a/tests/baselines/reference/importsNotUsedAsValues_error.symbols b/tests/baselines/reference/importsNotUsedAsValues_error.symbols index bc6b9ec5be8..28fcb0ff1d9 100644 --- a/tests/baselines/reference/importsNotUsedAsValues_error.symbols +++ b/tests/baselines/reference/importsNotUsedAsValues_error.symbols @@ -132,3 +132,48 @@ console.log(c, d); >c : Symbol(c, Decl(g.ts, 1, 3)) >d : Symbol(d, Decl(g.ts, 2, 3)) +=== /h.ts === +class H {} +>H : Symbol(H, Decl(h.ts, 0, 0)) + +export = H; +>H : Symbol(H, Decl(h.ts, 0, 0)) + +=== /i.ts === +import H = require('./h'); // Error +>H : Symbol(H, Decl(i.ts, 0, 0)) + +let h: H = {}; +>h : Symbol(h, Decl(i.ts, 1, 3)) +>H : Symbol(H, Decl(i.ts, 0, 0)) + +console.log(h); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>h : Symbol(h, Decl(i.ts, 1, 3)) + +=== /j.ts === +import H = require('./h'); // noUnusedLocals error only +No type information for this code. +No type information for this code.=== /k.ts === +const enum K { One, Two } +>K : Symbol(K, Decl(k.ts, 0, 0)) +>One : Symbol(K.One, Decl(k.ts, 0, 14)) +>Two : Symbol(K.Two, Decl(k.ts, 0, 19)) + +export = K; +>K : Symbol(K, Decl(k.ts, 0, 0)) + +=== /l.ts === +import K = require('./k'); +>K : Symbol(K, Decl(l.ts, 0, 0)) + +K.One; +>K.One : Symbol(K.One, Decl(k.ts, 0, 14)) +>K : Symbol(K, Decl(l.ts, 0, 0)) +>One : Symbol(K.One, Decl(k.ts, 0, 14)) + +=== /j.ts === +// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207 +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/importsNotUsedAsValues_error.types b/tests/baselines/reference/importsNotUsedAsValues_error.types index c7f0eb86ad9..cbe4fc62703 100644 --- a/tests/baselines/reference/importsNotUsedAsValues_error.types +++ b/tests/baselines/reference/importsNotUsedAsValues_error.types @@ -128,3 +128,49 @@ console.log(c, d); >c : C >d : C.Two +=== /h.ts === +class H {} +>H : H + +export = H; +>H : H + +=== /i.ts === +import H = require('./h'); // Error +>H : typeof H + +let h: H = {}; +>h : H +>{} : {} + +console.log(h); +>console.log(h) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>h : H + +=== /j.ts === +import H = require('./h'); // noUnusedLocals error only +No type information for this code. +No type information for this code.=== /k.ts === +const enum K { One, Two } +>K : K +>One : K.One +>Two : K.Two + +export = K; +>K : K + +=== /l.ts === +import K = require('./k'); +>K : typeof K + +K.One; +>K.One : K.One +>K : typeof K +>One : K.One + +=== /j.ts === +// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207 +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js b/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js index 8fa5d8b885b..7d8fe90cb85 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js +++ b/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js @@ -31,7 +31,7 @@ Output:: >> Screen clear [12:00:15 AM] Starting compilation in watch mode... -a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. 1 import {B} from './b'   ~~~~~~~~~~~~~~~~~~~~~ @@ -110,7 +110,7 @@ Output:: >> Screen clear [12:00:23 AM] File change detected. Starting incremental compilation... -a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. 1 import {B} from './b'   ~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js b/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js index 0bea4e7d87d..494fa61843a 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js +++ b/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js @@ -148,7 +148,7 @@ Output:: >> Screen clear [12:00:43 AM] File change detected. Starting incremental compilation... -b.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'. +b.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. 1 import {C} from './a';   ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/cases/conformance/externalModules/typeOnly/cjsImportInES2015.ts b/tests/cases/conformance/externalModules/typeOnly/cjsImportInES2015.ts new file mode 100644 index 00000000000..bcc9b5ab319 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/cjsImportInES2015.ts @@ -0,0 +1,10 @@ +// @module: es2015 +// @moduleResolution: node + +// @Filename: /project/node_modules/cjs-dep/index.d.ts +declare class SpecialError extends Error {} +export = SpecialError; + +// @Filename: /project/index.ts +import type SpecialError = require("cjs-dep"); +function handleError(err: SpecialError) {} diff --git a/tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts b/tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts index e16efa45f91..caec1c7284c 100644 --- a/tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts +++ b/tests/cases/conformance/externalModules/typeOnly/grammarErrors.ts @@ -13,3 +13,9 @@ import type A, { B, C } from './a'; // @Filename: /a.js import type A from './a'; export type { A }; + +// @Filename: /c.ts +namespace ns { + export class Foo {} +} +import type Foo = ns.Foo; diff --git a/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclaration.ts b/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclaration.ts new file mode 100644 index 00000000000..29870a78809 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclaration.ts @@ -0,0 +1,19 @@ +// @noTypesAndSymbols: true +// @declaration: true + +// @Filename: /a.ts +class A { a!: string } +export = A; + +// @Filename: /b.ts +class SomeClass {} +export = SomeClass; + +// @Filename: /c.ts +import type A = require('./a'); // Ok +import type = require('./b'); // Ok + +A.prototype; // Error +const a: A = { a: 'a' }; // Ok +void type; // Ok +export declare const AConstructor: typeof A; // Ok diff --git a/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclarationError.ts b/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclarationError.ts deleted file mode 100644 index f3b40cd48dc..00000000000 --- a/tests/cases/conformance/externalModules/typeOnly/importEqualsDeclarationError.ts +++ /dev/null @@ -1,14 +0,0 @@ -// @noEmit: true -// @noTypesAndSymbols: true - -// @Filename: /a.ts -type T = {}; -export = T; - -// @Filename: /b.ts -class SomeClass {} -export = SomeClass; - -// @Filename: /c.ts -import type T = require('./a'); // Error -import type = require('./b'); // Ok diff --git a/tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValues_error.ts b/tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValues_error.ts index aa67936654d..ae697e7c3cb 100644 --- a/tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValues_error.ts +++ b/tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValues_error.ts @@ -40,4 +40,27 @@ console.log(c, d); import { C } from './a'; let c: C; let d: C.Two; -console.log(c, d); \ No newline at end of file +console.log(c, d); + +// @Filename: /h.ts +class H {} +export = H; + +// @Filename: /i.ts +import H = require('./h'); // Error +let h: H = {}; +console.log(h); + +// @Filename: /j.ts +import H = require('./h'); // noUnusedLocals error only + +// @Filename: /k.ts +const enum K { One, Two } +export = K; + +// @Filename: /l.ts +import K = require('./k'); +K.One; + +// @Filename: /j.ts +// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207 \ No newline at end of file From cd37a327a71350a232642ed4792f0aba8a930e01 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 3 Dec 2020 18:36:45 -0800 Subject: [PATCH 6/6] Fix non-homomorphic mapped type constraint issues (#41807) * Less aggressive wildcard check, 'keyof any' constraint for 'infer T' in mapped type constraint position * Accept new baselines * Add regression tests --- src/compiler/checker.ts | 8 ++- .../reference/recursiveMappedTypes.errors.txt | 18 ++++-- .../reference/recursiveMappedTypes.js | 18 ++++++ .../reference/recursiveMappedTypes.symbols | 61 +++++++++++++++++++ .../reference/recursiveMappedTypes.types | 18 ++++++ .../types/mapped/recursiveMappedTypes.ts | 12 ++++ 6 files changed, 128 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ea35af4c80d..413360d6d2a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12081,6 +12081,11 @@ namespace ts { else if (grandParent.kind === SyntaxKind.TemplateLiteralTypeSpan) { inferences = append(inferences, stringType); } + // When an 'infer T' declaration is in the constraint position of a mapped type, we infer a 'keyof any' + // constraint. + else if (grandParent.kind === SyntaxKind.TypeParameter && grandParent.parent.kind === SyntaxKind.MappedType) { + inferences = append(inferences, keyofConstraintType); + } } } } @@ -15281,8 +15286,7 @@ namespace ts { } } // If the constraint type of the instantiation is the wildcard type, return the wildcard type. - const result = instantiateAnonymousType(type, mapper); - return getConstraintTypeFromMappedType(result) === wildcardType ? wildcardType : result; + return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper); } function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) { diff --git a/tests/baselines/reference/recursiveMappedTypes.errors.txt b/tests/baselines/reference/recursiveMappedTypes.errors.txt index 56a9d1c0214..1a912efef0f 100644 --- a/tests/baselines/reference/recursiveMappedTypes.errors.txt +++ b/tests/baselines/reference/recursiveMappedTypes.errors.txt @@ -5,12 +5,11 @@ tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(8,11): error TS2313 tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(11,6): error TS2456: Type alias 'Recurse2' circularly references itself. tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(12,11): error TS2313: Type parameter 'K' has a circular constraint. tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(20,19): error TS2589: Type instantiation is excessively deep and possibly infinite. -tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(66,25): error TS2313: Type parameter 'P' has a circular constraint. tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(73,5): error TS2502: '"each"' is referenced directly or indirectly in its own type annotation. tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(73,13): error TS2615: Type of property '"each"' circularly references itself in mapped type '{ [P in keyof ListWidget]: undefined extends ListWidget[P] ? never : P; }'. -==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (10 errors) ==== +==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (9 errors) ==== // Recursive mapped types simply appear empty type Recurse = { @@ -92,9 +91,6 @@ tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(73,13): error TS261 type NonOptionalKeys = { [P in keyof T]: undefined extends T[P] ? never : P }[keyof T]; type Child = { [P in NonOptionalKeys]: T[P] } - ~~~~~~~~~~~~~~~~~~ -!!! error TS2313: Type parameter 'P' has a circular constraint. -!!! related TS2751 tests/cases/conformance/types/mapped/recursiveMappedTypes.ts:73:13: Circularity originates in type at this location. export interface ListWidget { "type": "list", @@ -112,4 +108,16 @@ tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(73,13): error TS261 declare let x: ListChild; x.type; + + // Repros from #41790 + + export type TV = T[K] extends Record ? E : never; + + export type ObjectOrArray = T[] | Record | T[]>; + export type ThemeValue = + ThemeType[K] extends TVal[] ? number : + ThemeType[K] extends Record ? E : + ThemeType[K] extends ObjectOrArray ? F : never; + + export type Foo = T extends { [P in infer E]: any } ? E : never; \ No newline at end of file diff --git a/tests/baselines/reference/recursiveMappedTypes.js b/tests/baselines/reference/recursiveMappedTypes.js index 2cda37a8d45..142ce6effb3 100644 --- a/tests/baselines/reference/recursiveMappedTypes.js +++ b/tests/baselines/reference/recursiveMappedTypes.js @@ -78,6 +78,18 @@ type ListChild = Child declare let x: ListChild; x.type; + +// Repros from #41790 + +export type TV = T[K] extends Record ? E : never; + +export type ObjectOrArray = T[] | Record | T[]>; +export type ThemeValue = + ThemeType[K] extends TVal[] ? number : + ThemeType[K] extends Record ? E : + ThemeType[K] extends ObjectOrArray ? F : never; + +export type Foo = T extends { [P in infer E]: any } ? E : never; //// [recursiveMappedTypes.js] @@ -108,4 +120,10 @@ export interface ListWidget { "collapsable"?: boolean; "each": Child; } +export declare type TV = T[K] extends Record ? E : never; +export declare type ObjectOrArray = T[] | Record | T[]>; +export declare type ThemeValue = ThemeType[K] extends TVal[] ? number : ThemeType[K] extends Record ? E : ThemeType[K] extends ObjectOrArray ? F : never; +export declare type Foo = T extends { + [P in infer E]: any; +} ? E : never; export {}; diff --git a/tests/baselines/reference/recursiveMappedTypes.symbols b/tests/baselines/reference/recursiveMappedTypes.symbols index 777a6a722fa..62f9987c995 100644 --- a/tests/baselines/reference/recursiveMappedTypes.symbols +++ b/tests/baselines/reference/recursiveMappedTypes.symbols @@ -219,3 +219,64 @@ declare let x: ListChild; x.type; >x : Symbol(x, Decl(recursiveMappedTypes.ts, 77, 11)) +// Repros from #41790 + +export type TV = T[K] extends Record ? E : never; +>TV : Symbol(TV, Decl(recursiveMappedTypes.ts, 78, 7)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 82, 15)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 82, 17)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 82, 15)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 82, 15)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 82, 17)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>E : Symbol(E, Decl(recursiveMappedTypes.ts, 82, 64)) +>E : Symbol(E, Decl(recursiveMappedTypes.ts, 82, 64)) + +export type ObjectOrArray = T[] | Record | T[]>; +>ObjectOrArray : Symbol(ObjectOrArray, Decl(recursiveMappedTypes.ts, 82, 85)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 84, 26)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 84, 28)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 84, 26)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 84, 28)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 84, 26)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 84, 28)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 84, 26)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 84, 26)) + +export type ThemeValue = +>ThemeValue : Symbol(ThemeValue, Decl(recursiveMappedTypes.ts, 84, 104)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 85, 23)) +>ThemeType : Symbol(ThemeType, Decl(recursiveMappedTypes.ts, 85, 49)) +>ThemeType : Symbol(ThemeType, Decl(recursiveMappedTypes.ts, 85, 49)) +>TVal : Symbol(TVal, Decl(recursiveMappedTypes.ts, 85, 60)) + + ThemeType[K] extends TVal[] ? number : +>ThemeType : Symbol(ThemeType, Decl(recursiveMappedTypes.ts, 85, 49)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 85, 23)) +>TVal : Symbol(TVal, Decl(recursiveMappedTypes.ts, 85, 60)) + + ThemeType[K] extends Record ? E : +>ThemeType : Symbol(ThemeType, Decl(recursiveMappedTypes.ts, 85, 49)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 85, 23)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>E : Symbol(E, Decl(recursiveMappedTypes.ts, 87, 37)) +>TVal : Symbol(TVal, Decl(recursiveMappedTypes.ts, 85, 60)) +>E : Symbol(E, Decl(recursiveMappedTypes.ts, 87, 37)) + + ThemeType[K] extends ObjectOrArray ? F : never; +>ThemeType : Symbol(ThemeType, Decl(recursiveMappedTypes.ts, 85, 49)) +>K : Symbol(K, Decl(recursiveMappedTypes.ts, 85, 23)) +>ObjectOrArray : Symbol(ObjectOrArray, Decl(recursiveMappedTypes.ts, 82, 85)) +>F : Symbol(F, Decl(recursiveMappedTypes.ts, 88, 44)) +>F : Symbol(F, Decl(recursiveMappedTypes.ts, 88, 44)) + +export type Foo = T extends { [P in infer E]: any } ? E : never; +>Foo : Symbol(Foo, Decl(recursiveMappedTypes.ts, 88, 60)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 90, 16)) +>T : Symbol(T, Decl(recursiveMappedTypes.ts, 90, 16)) +>P : Symbol(P, Decl(recursiveMappedTypes.ts, 90, 34)) +>E : Symbol(E, Decl(recursiveMappedTypes.ts, 90, 44)) +>E : Symbol(E, Decl(recursiveMappedTypes.ts, 90, 44)) + diff --git a/tests/baselines/reference/recursiveMappedTypes.types b/tests/baselines/reference/recursiveMappedTypes.types index a3ebe7e60c0..83447fbb787 100644 --- a/tests/baselines/reference/recursiveMappedTypes.types +++ b/tests/baselines/reference/recursiveMappedTypes.types @@ -133,3 +133,21 @@ x.type; >x : Child >type : any +// Repros from #41790 + +export type TV = T[K] extends Record ? E : never; +>TV : TV + +export type ObjectOrArray = T[] | Record | T[]>; +>ObjectOrArray : ObjectOrArray + +export type ThemeValue = +>ThemeValue : ThemeValue + + ThemeType[K] extends TVal[] ? number : + ThemeType[K] extends Record ? E : + ThemeType[K] extends ObjectOrArray ? F : never; + +export type Foo = T extends { [P in infer E]: any } ? E : never; +>Foo : Foo + diff --git a/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts b/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts index d5a5d63515f..da790a1b543 100644 --- a/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts +++ b/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts @@ -79,3 +79,15 @@ type ListChild = Child declare let x: ListChild; x.type; + +// Repros from #41790 + +export type TV = T[K] extends Record ? E : never; + +export type ObjectOrArray = T[] | Record | T[]>; +export type ThemeValue = + ThemeType[K] extends TVal[] ? number : + ThemeType[K] extends Record ? E : + ThemeType[K] extends ObjectOrArray ? F : never; + +export type Foo = T extends { [P in infer E]: any } ? E : never;