From 1354226eae2c2be68ad110ab1bbbeb5494019607 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 27 Jan 2020 08:30:58 -0800 Subject: [PATCH 1/3] Add test --- .../externalModules/typeOnly/implementsClause.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/cases/conformance/externalModules/typeOnly/implementsClause.ts diff --git a/tests/cases/conformance/externalModules/typeOnly/implementsClause.ts b/tests/cases/conformance/externalModules/typeOnly/implementsClause.ts new file mode 100644 index 0000000000000..8d018934a8e30 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/implementsClause.ts @@ -0,0 +1,6 @@ +// @Filename: types.ts +export interface Component {} + +// @Filename: index.ts +import type * as types from './types'; +class C implements types.Component {} \ No newline at end of file From c0079055399382fc1085b53bcf536d6c5fdcea19 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 27 Jan 2020 14:16:48 -0800 Subject: [PATCH 2/3] Allow type-only symbols in implements clauses --- src/compiler/utilities.ts | 6 ++++++ tests/baselines/reference/implementsClause.js | 20 +++++++++++++++++++ .../reference/implementsClause.symbols | 14 +++++++++++++ .../reference/implementsClause.types | 11 ++++++++++ 4 files changed, 51 insertions(+) create mode 100644 tests/baselines/reference/implementsClause.js create mode 100644 tests/baselines/reference/implementsClause.symbols create mode 100644 tests/baselines/reference/implementsClause.types diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a0cac0d375331..167ee1aef2a91 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1792,6 +1792,11 @@ namespace ts { return containerKind === SyntaxKind.InterfaceDeclaration || containerKind === SyntaxKind.TypeLiteral; } + export function isFirstIdentifierOfImplementsClause(node: Node) { + return node.parent?.parent?.parent?.kind === SyntaxKind.HeritageClause + && (node.parent.parent.parent as HeritageClause).token === SyntaxKind.ImplementsKeyword; + } + export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } { return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference; } @@ -6138,6 +6143,7 @@ namespace ts { export function isValidTypeOnlyAliasUseSite(useSite: Node): boolean { return !!(useSite.flags & NodeFlags.Ambient) || isPartOfTypeQuery(useSite) + || isFirstIdentifierOfImplementsClause(useSite) || isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(useSite) || !isExpressionNode(useSite); } diff --git a/tests/baselines/reference/implementsClause.js b/tests/baselines/reference/implementsClause.js new file mode 100644 index 0000000000000..f9638d22be2a5 --- /dev/null +++ b/tests/baselines/reference/implementsClause.js @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/externalModules/typeOnly/implementsClause.ts] //// + +//// [types.ts] +export interface Component {} + +//// [index.ts] +import type * as types from './types'; +class C implements types.Component {} + +//// [types.js] +"use strict"; +exports.__esModule = true; +//// [index.js] +"use strict"; +exports.__esModule = true; +var C = /** @class */ (function () { + function C() { + } + return C; +}()); diff --git a/tests/baselines/reference/implementsClause.symbols b/tests/baselines/reference/implementsClause.symbols new file mode 100644 index 0000000000000..eeadcfdbcd9f5 --- /dev/null +++ b/tests/baselines/reference/implementsClause.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/externalModules/typeOnly/types.ts === +export interface Component {} +>Component : Symbol(Component, Decl(types.ts, 0, 0)) + +=== tests/cases/conformance/externalModules/typeOnly/index.ts === +import type * as types from './types'; +>types : Symbol(types, Decl(index.ts, 0, 11)) + +class C implements types.Component {} +>C : Symbol(C, Decl(index.ts, 0, 38)) +>types.Component : Symbol(types.Component, Decl(types.ts, 0, 0)) +>types : Symbol(types, Decl(index.ts, 0, 11)) +>Component : Symbol(types.Component, Decl(types.ts, 0, 0)) + diff --git a/tests/baselines/reference/implementsClause.types b/tests/baselines/reference/implementsClause.types new file mode 100644 index 0000000000000..7a216ec318d96 --- /dev/null +++ b/tests/baselines/reference/implementsClause.types @@ -0,0 +1,11 @@ +=== tests/cases/conformance/externalModules/typeOnly/types.ts === +export interface Component {} +No type information for this code. +No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/index.ts === +import type * as types from './types'; +>types : typeof types + +class C implements types.Component {} +>C : C +>types : typeof types + From 8c74b61cf87dd14de8e144a0df942bcc2b3903f4 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 27 Jan 2020 15:09:57 -0800 Subject: [PATCH 3/3] Add more complex test --- tests/baselines/reference/implementsClause.js | 18 ++++++++++++++++- .../reference/implementsClause.symbols | 20 ++++++++++++++++++- .../reference/implementsClause.types | 18 ++++++++++++++++- .../typeOnly/implementsClause.ts | 9 ++++++++- 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/implementsClause.js b/tests/baselines/reference/implementsClause.js index f9638d22be2a5..431c9042f5b67 100644 --- a/tests/baselines/reference/implementsClause.js +++ b/tests/baselines/reference/implementsClause.js @@ -3,13 +3,24 @@ //// [types.ts] export interface Component {} +//// [ns.ts] +import type * as types from './types'; +export { types }; + //// [index.ts] import type * as types from './types'; -class C implements types.Component {} +import * as nestedNamespace from './ns'; + +class C implements types.Component {} +class D implements nestedNamespace.types.Component {} + //// [types.js] "use strict"; exports.__esModule = true; +//// [ns.js] +"use strict"; +exports.__esModule = true; //// [index.js] "use strict"; exports.__esModule = true; @@ -18,3 +29,8 @@ var C = /** @class */ (function () { } return C; }()); +var D = /** @class */ (function () { + function D() { + } + return D; +}()); diff --git a/tests/baselines/reference/implementsClause.symbols b/tests/baselines/reference/implementsClause.symbols index eeadcfdbcd9f5..b865e9187cb19 100644 --- a/tests/baselines/reference/implementsClause.symbols +++ b/tests/baselines/reference/implementsClause.symbols @@ -2,13 +2,31 @@ export interface Component {} >Component : Symbol(Component, Decl(types.ts, 0, 0)) +=== tests/cases/conformance/externalModules/typeOnly/ns.ts === +import type * as types from './types'; +>types : Symbol(types, Decl(ns.ts, 0, 11)) + +export { types }; +>types : Symbol(types, Decl(ns.ts, 1, 8)) + === tests/cases/conformance/externalModules/typeOnly/index.ts === import type * as types from './types'; >types : Symbol(types, Decl(index.ts, 0, 11)) +import * as nestedNamespace from './ns'; +>nestedNamespace : Symbol(nestedNamespace, Decl(index.ts, 1, 6)) + class C implements types.Component {} ->C : Symbol(C, Decl(index.ts, 0, 38)) +>C : Symbol(C, Decl(index.ts, 1, 40)) >types.Component : Symbol(types.Component, Decl(types.ts, 0, 0)) >types : Symbol(types, Decl(index.ts, 0, 11)) >Component : Symbol(types.Component, Decl(types.ts, 0, 0)) +class D implements nestedNamespace.types.Component {} +>D : Symbol(D, Decl(index.ts, 3, 37)) +>nestedNamespace.types.Component : Symbol(types.Component, Decl(types.ts, 0, 0)) +>nestedNamespace.types : Symbol(nestedNamespace.types, Decl(ns.ts, 1, 8)) +>nestedNamespace : Symbol(nestedNamespace, Decl(index.ts, 1, 6)) +>types : Symbol(nestedNamespace.types, Decl(ns.ts, 1, 8)) +>Component : Symbol(types.Component, Decl(types.ts, 0, 0)) + diff --git a/tests/baselines/reference/implementsClause.types b/tests/baselines/reference/implementsClause.types index 7a216ec318d96..ffdff2f6fb08d 100644 --- a/tests/baselines/reference/implementsClause.types +++ b/tests/baselines/reference/implementsClause.types @@ -1,11 +1,27 @@ === tests/cases/conformance/externalModules/typeOnly/types.ts === export interface Component {} No type information for this code. -No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/index.ts === +No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/ns.ts === import type * as types from './types'; >types : typeof types +export { types }; +>types : typeof types + +=== tests/cases/conformance/externalModules/typeOnly/index.ts === +import type * as types from './types'; +>types : typeof types + +import * as nestedNamespace from './ns'; +>nestedNamespace : typeof nestedNamespace + class C implements types.Component {} >C : C >types : typeof types +class D implements nestedNamespace.types.Component {} +>D : D +>nestedNamespace.types : any +>nestedNamespace : typeof nestedNamespace +>types : any + diff --git a/tests/cases/conformance/externalModules/typeOnly/implementsClause.ts b/tests/cases/conformance/externalModules/typeOnly/implementsClause.ts index 8d018934a8e30..71926627d2470 100644 --- a/tests/cases/conformance/externalModules/typeOnly/implementsClause.ts +++ b/tests/cases/conformance/externalModules/typeOnly/implementsClause.ts @@ -1,6 +1,13 @@ // @Filename: types.ts export interface Component {} +// @Filename: ns.ts +import type * as types from './types'; +export { types }; + // @Filename: index.ts import type * as types from './types'; -class C implements types.Component {} \ No newline at end of file +import * as nestedNamespace from './ns'; + +class C implements types.Component {} +class D implements nestedNamespace.types.Component {}