Skip to content

Commit 7e1382a

Browse files
committed
Fix interface extends clause
1 parent 2e47d4a commit 7e1382a

File tree

6 files changed

+209
-4
lines changed

6 files changed

+209
-4
lines changed

src/compiler/utilities.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1792,9 +1792,10 @@ namespace ts {
17921792
return containerKind === SyntaxKind.InterfaceDeclaration || containerKind === SyntaxKind.TypeLiteral;
17931793
}
17941794

1795-
export function isFirstIdentifierOfImplementsClause(node: Node) {
1796-
return node.parent?.parent?.parent?.kind === SyntaxKind.HeritageClause
1797-
&& (node.parent.parent.parent as HeritageClause).token === SyntaxKind.ImplementsKeyword;
1795+
export function isFirstIdentifierOfNonEmittingHeritageClause(node: Node): boolean {
1796+
// Number of parents to climb from identifier is 2 for `implements I`, 3 for `implements x.I`
1797+
const heritageClause = tryCast(node.parent.parent, isHeritageClause) ?? tryCast(node.parent.parent.parent, isHeritageClause);
1798+
return heritageClause?.token === SyntaxKind.ImplementsKeyword || heritageClause?.parent.kind === SyntaxKind.InterfaceDeclaration;
17981799
}
17991800

18001801
export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } {
@@ -6143,7 +6144,7 @@ namespace ts {
61436144
export function isValidTypeOnlyAliasUseSite(useSite: Node): boolean {
61446145
return !!(useSite.flags & NodeFlags.Ambient)
61456146
|| isPartOfTypeQuery(useSite)
6146-
|| isFirstIdentifierOfImplementsClause(useSite)
6147+
|| isFirstIdentifierOfNonEmittingHeritageClause(useSite)
61476148
|| isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(useSite)
61486149
|| !isExpressionNode(useSite);
61496150
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
tests/cases/conformance/externalModules/typeOnly/index.ts(9,17): error TS1361: 'C' cannot be used as a value because it was imported using 'import type'.
2+
tests/cases/conformance/externalModules/typeOnly/index.ts(10,17): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
3+
4+
5+
==== tests/cases/conformance/externalModules/typeOnly/types.ts (0 errors) ====
6+
export interface I {}
7+
export class C {}
8+
9+
==== tests/cases/conformance/externalModules/typeOnly/ns.ts (0 errors) ====
10+
import type * as types from './types';
11+
export { types };
12+
13+
==== tests/cases/conformance/externalModules/typeOnly/index.ts (2 errors) ====
14+
import { types } from './ns';
15+
import type { C, I } from './types';
16+
17+
interface Q extends C {}
18+
interface R extends I {}
19+
interface S extends types.C {}
20+
interface T extends types.I {}
21+
22+
class U extends C {} // Error
23+
~
24+
!!! error TS1361: 'C' cannot be used as a value because it was imported using 'import type'.
25+
!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/index.ts:2:15: 'C' was imported here.
26+
class V extends types.C {} // Error
27+
~~~~~
28+
!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
29+
!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/ns.ts:1:13: 'types' was imported here.
30+
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/extendsClause.ts] ////
2+
3+
//// [types.ts]
4+
export interface I {}
5+
export class C {}
6+
7+
//// [ns.ts]
8+
import type * as types from './types';
9+
export { types };
10+
11+
//// [index.ts]
12+
import { types } from './ns';
13+
import type { C, I } from './types';
14+
15+
interface Q extends C {}
16+
interface R extends I {}
17+
interface S extends types.C {}
18+
interface T extends types.I {}
19+
20+
class U extends C {} // Error
21+
class V extends types.C {} // Error
22+
23+
24+
//// [types.js]
25+
"use strict";
26+
exports.__esModule = true;
27+
var C = /** @class */ (function () {
28+
function C() {
29+
}
30+
return C;
31+
}());
32+
exports.C = C;
33+
//// [ns.js]
34+
"use strict";
35+
exports.__esModule = true;
36+
//// [index.js]
37+
"use strict";
38+
var __extends = (this && this.__extends) || (function () {
39+
var extendStatics = function (d, b) {
40+
extendStatics = Object.setPrototypeOf ||
41+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
42+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
43+
return extendStatics(d, b);
44+
};
45+
return function (d, b) {
46+
extendStatics(d, b);
47+
function __() { this.constructor = d; }
48+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
49+
};
50+
})();
51+
exports.__esModule = true;
52+
var U = /** @class */ (function (_super) {
53+
__extends(U, _super);
54+
function U() {
55+
return _super !== null && _super.apply(this, arguments) || this;
56+
}
57+
return U;
58+
}(C)); // Error
59+
var V = /** @class */ (function (_super) {
60+
__extends(V, _super);
61+
function V() {
62+
return _super !== null && _super.apply(this, arguments) || this;
63+
}
64+
return V;
65+
}(types.C)); // Error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
=== tests/cases/conformance/externalModules/typeOnly/types.ts ===
2+
export interface I {}
3+
>I : Symbol(I, Decl(types.ts, 0, 0))
4+
5+
export class C {}
6+
>C : Symbol(C, Decl(types.ts, 0, 21))
7+
8+
=== tests/cases/conformance/externalModules/typeOnly/ns.ts ===
9+
import type * as types from './types';
10+
>types : Symbol(types, Decl(ns.ts, 0, 11))
11+
12+
export { types };
13+
>types : Symbol(types, Decl(ns.ts, 1, 8))
14+
15+
=== tests/cases/conformance/externalModules/typeOnly/index.ts ===
16+
import { types } from './ns';
17+
>types : Symbol(types, Decl(index.ts, 0, 8))
18+
19+
import type { C, I } from './types';
20+
>C : Symbol(C, Decl(index.ts, 1, 13))
21+
>I : Symbol(I, Decl(index.ts, 1, 16))
22+
23+
interface Q extends C {}
24+
>Q : Symbol(Q, Decl(index.ts, 1, 36))
25+
>C : Symbol(C, Decl(index.ts, 1, 13))
26+
27+
interface R extends I {}
28+
>R : Symbol(R, Decl(index.ts, 3, 24))
29+
>I : Symbol(I, Decl(index.ts, 1, 16))
30+
31+
interface S extends types.C {}
32+
>S : Symbol(S, Decl(index.ts, 4, 24))
33+
>types.C : Symbol(types.C, Decl(types.ts, 0, 21))
34+
>types : Symbol(types, Decl(index.ts, 0, 8))
35+
>C : Symbol(types.C, Decl(types.ts, 0, 21))
36+
37+
interface T extends types.I {}
38+
>T : Symbol(T, Decl(index.ts, 5, 30))
39+
>types.I : Symbol(types.I, Decl(types.ts, 0, 0))
40+
>types : Symbol(types, Decl(index.ts, 0, 8))
41+
>I : Symbol(types.I, Decl(types.ts, 0, 0))
42+
43+
class U extends C {} // Error
44+
>U : Symbol(U, Decl(index.ts, 6, 30))
45+
>C : Symbol(C, Decl(index.ts, 1, 13))
46+
47+
class V extends types.C {} // Error
48+
>V : Symbol(V, Decl(index.ts, 8, 20))
49+
>types.C : Symbol(types.C, Decl(types.ts, 0, 21))
50+
>types : Symbol(types, Decl(index.ts, 0, 8))
51+
>C : Symbol(types.C, Decl(types.ts, 0, 21))
52+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
=== tests/cases/conformance/externalModules/typeOnly/types.ts ===
2+
export interface I {}
3+
export class C {}
4+
>C : C
5+
6+
=== tests/cases/conformance/externalModules/typeOnly/ns.ts ===
7+
import type * as types from './types';
8+
>types : typeof types
9+
10+
export { types };
11+
>types : typeof types
12+
13+
=== tests/cases/conformance/externalModules/typeOnly/index.ts ===
14+
import { types } from './ns';
15+
>types : typeof types
16+
17+
import type { C, I } from './types';
18+
>C : types.C
19+
>I : types.I
20+
21+
interface Q extends C {}
22+
interface R extends I {}
23+
interface S extends types.C {}
24+
>types : typeof types
25+
26+
interface T extends types.I {}
27+
>types : typeof types
28+
29+
class U extends C {} // Error
30+
>U : U
31+
>C : types.C
32+
33+
class V extends types.C {} // Error
34+
>V : V
35+
>types.C : types.C
36+
>types : typeof types
37+
>C : typeof types.C
38+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @Filename: types.ts
2+
export interface I {}
3+
export class C {}
4+
5+
// @Filename: ns.ts
6+
import type * as types from './types';
7+
export { types };
8+
9+
// @Filename: index.ts
10+
import { types } from './ns';
11+
import type { C, I } from './types';
12+
13+
interface Q extends C {}
14+
interface R extends I {}
15+
interface S extends types.C {}
16+
interface T extends types.I {}
17+
18+
class U extends C {} // Error
19+
class V extends types.C {} // Error

0 commit comments

Comments
 (0)