Fix longer type-only property access in non-emitting heritage clauses (#37264)

* Fix longer type-only property access in non-emitting heritage clauses

* Rename misnomer function
This commit is contained in:
Andrew Branch 2020-03-09 11:05:36 -08:00 committed by GitHub
parent 8d63a7a842
commit bc0e5a241c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 5 deletions

View file

@ -6267,7 +6267,7 @@ namespace ts {
export function isValidTypeOnlyAliasUseSite(useSite: Node): boolean {
return !!(useSite.flags & NodeFlags.Ambient)
|| isPartOfTypeQuery(useSite)
|| isFirstIdentifierOfNonEmittingHeritageClause(useSite)
|| isIdentifierInNonEmittingHeritageClause(useSite)
|| isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(useSite)
|| !isExpressionNode(useSite);
}
@ -6290,10 +6290,20 @@ namespace ts {
return containerKind === SyntaxKind.InterfaceDeclaration || containerKind === SyntaxKind.TypeLiteral;
}
/** Returns true for the first identifier of 1) an `implements` clause, and 2) an `extends` clause of an interface. */
function isFirstIdentifierOfNonEmittingHeritageClause(node: Node): boolean {
// Number of parents to climb from identifier is 2 for `implements I`, 3 for `implements x.I`
const heritageClause = tryCast(node.parent.parent, isHeritageClause) ?? tryCast(node.parent.parent?.parent, isHeritageClause);
/** Returns true for an identifier in 1) an `implements` clause, and 2) an `extends` clause of an interface. */
function isIdentifierInNonEmittingHeritageClause(node: Node): boolean {
if (node.kind !== SyntaxKind.Identifier) return false;
const heritageClause = findAncestor(node.parent, parent => {
switch (parent.kind) {
case SyntaxKind.HeritageClause:
return true;
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ExpressionWithTypeArguments:
return false;
default:
return "quit";
}
}) as HeritageClause | undefined;
return heritageClause?.token === SyntaxKind.ImplementsKeyword || heritageClause?.parent.kind === SyntaxKind.InterfaceDeclaration;
}
}

View file

@ -0,0 +1,28 @@
//// [tests/cases/conformance/externalModules/typeOnly/nestedNamespace.ts] ////
//// [a.ts]
export namespace types {
export class A {}
}
//// [b.ts]
import type * as a from './a';
interface B extends a.types.A {}
//// [a.js]
"use strict";
exports.__esModule = true;
exports.types = void 0;
var types;
(function (types) {
var A = /** @class */ (function () {
function A() {
}
return A;
}());
types.A = A;
})(types = exports.types || (exports.types = {}));
//// [b.js]
"use strict";
exports.__esModule = true;

View file

@ -0,0 +1,20 @@
=== tests/cases/conformance/externalModules/typeOnly/a.ts ===
export namespace types {
>types : Symbol(types, Decl(a.ts, 0, 0))
export class A {}
>A : Symbol(A, Decl(a.ts, 0, 24))
}
=== tests/cases/conformance/externalModules/typeOnly/b.ts ===
import type * as a from './a';
>a : Symbol(a, Decl(b.ts, 0, 11))
interface B extends a.types.A {}
>B : Symbol(B, Decl(b.ts, 0, 30))
>a.types.A : Symbol(a.types.A, Decl(a.ts, 0, 24))
>a.types : Symbol(a.types, Decl(a.ts, 0, 0))
>a : Symbol(a, Decl(b.ts, 0, 11))
>types : Symbol(a.types, Decl(a.ts, 0, 0))
>A : Symbol(a.types.A, Decl(a.ts, 0, 24))

View file

@ -0,0 +1,17 @@
=== tests/cases/conformance/externalModules/typeOnly/a.ts ===
export namespace types {
>types : typeof types
export class A {}
>A : A
}
=== tests/cases/conformance/externalModules/typeOnly/b.ts ===
import type * as a from './a';
>a : typeof a
interface B extends a.types.A {}
>a.types : typeof a.types
>a : typeof a
>types : typeof a.types

View file

@ -0,0 +1,8 @@
// @Filename: a.ts
export namespace types {
export class A {}
}
// @Filename: b.ts
import type * as a from './a';
interface B extends a.types.A {}