Skip to content

Commit 7ddb796

Browse files
Fixed declaration emit for @interface
1 parent d7839fe commit 7ddb796

30 files changed

+283
-36
lines changed

src/compiler/checker.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5696,9 +5696,13 @@ namespace ts {
56965696
const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context));
56975697
const classType = getDeclaredTypeOfClassOrInterface(symbol);
56985698
const baseTypes = getBaseTypes(classType);
5699+
const implementsTypes = getImplementsTypes(classType);
56995700
const staticType = getTypeOfSymbol(symbol);
57005701
const staticBaseType = getBaseConstructorTypeOfClass(staticType as InterfaceType);
5701-
const heritageClauses = !length(baseTypes) ? undefined : [createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))];
5702+
const heritageClauses = [
5703+
...!length(baseTypes) ? [] : [createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))],
5704+
...!length(implementsTypes) ? [] : [createHeritageClause(SyntaxKind.ImplementsKeyword, map(implementsTypes, b => serializeBaseType(b, staticBaseType, localName)))]
5705+
];
57025706
const symbolProps = getPropertiesOfType(classType);
57035707
const publicSymbolProps = filter(symbolProps, s => {
57045708
const valueDecl = s.valueDeclaration;
@@ -8063,6 +8067,17 @@ namespace ts {
80638067
return type.resolvedBaseConstructorType;
80648068
}
80658069

8070+
function getImplementsTypes(type: InterfaceType): BaseType[] {
8071+
if (!type.resolvedImplementsTypes) {
8072+
if (type.symbol.flags & SymbolFlags.Class) {
8073+
resolveImplementsTypesOfClass(type);
8074+
}
8075+
else {
8076+
Debug.fail("type must be an interface");
8077+
}
8078+
}
8079+
return type.resolvedImplementsTypes;
8080+
}
80668081
function getBaseTypes(type: InterfaceType): BaseType[] {
80678082
if (!type.resolvedBaseTypes) {
80688083
if (type.objectFlags & ObjectFlags.Tuple) {
@@ -8162,6 +8177,29 @@ namespace ts {
81628177
!!(type.flags & TypeFlags.Intersection) && every((<IntersectionType>type).types, isValidBaseType);
81638178
}
81648179

8180+
function resolveImplementsTypesOfClass(type: InterfaceType) {
8181+
type.resolvedImplementsTypes = type.resolvedImplementsTypes || emptyArray;
8182+
for (const declaration of type.symbol.declarations) {
8183+
8184+
if (!isClassLike(declaration)) continue;
8185+
8186+
const implementsTypeNodes = getEffectiveImplementsTypeNodes(declaration);
8187+
8188+
if (!implementsTypeNodes) continue;
8189+
8190+
for (const node of implementsTypeNodes) {
8191+
const implementsType = getTypeFromTypeNode(node);
8192+
if (implementsType !== errorType) {
8193+
if (type.resolvedImplementsTypes === emptyArray) {
8194+
type.resolvedImplementsTypes = [<ObjectType>implementsType];
8195+
}
8196+
else {
8197+
type.resolvedImplementsTypes.push(implementsType);
8198+
}
8199+
}
8200+
}
8201+
}
8202+
}
81658203
function resolveBaseTypesOfInterface(type: InterfaceType): void {
81668204
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
81678205
for (const declaration of type.symbol.declarations) {

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4468,6 +4468,8 @@ namespace ts {
44684468
resolvedBaseConstructorType?: Type; // Resolved base constructor type of class
44694469
/* @internal */
44704470
resolvedBaseTypes: BaseType[]; // Resolved base types
4471+
/* @internal */
4472+
resolvedImplementsTypes: BaseType[]; // Resolved implements types
44714473
}
44724474

44734475
// Object type or intersection of object types

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2775,7 +2775,7 @@ namespace ts {
27752775
}
27762776
else {
27772777
const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword);
2778-
return heritageClause ? heritageClause.types : undefined;
2778+
return heritageClause?.types;
27792779
}
27802780
}
27812781

tests/baselines/reference/jsdocImplements_class.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/** @return {number} */
1111
method() { throw new Error(); }
1212
}
13-
/** @implements A */
13+
/** @implements {A} */
1414
class B {
1515
method() { return 0 }
1616
}
@@ -25,7 +25,7 @@
2525
!!! error TS2416: Type 'string' is not assignable to type 'number'.
2626
}
2727

28-
/** @implements A */
28+
/** @implements {A} */
2929
class B3 {
3030
~~
3131
!!! error TS2720: Class 'B3' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass?
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [a.js]
2+
class A {
3+
/** @return {number} */
4+
method() { throw new Error(); }
5+
}
6+
/** @implements {A} */
7+
class B {
8+
method() { return 0 }
9+
}
10+
11+
/** @implements A */
12+
class B2 {
13+
/** @return {string} */
14+
method() { return "" }
15+
}
16+
17+
/** @implements {A} */
18+
class B3 {
19+
}
20+
21+
22+
23+
24+
//// [a.d.ts]
25+
declare class A {
26+
/** @return {number} */
27+
method(): number;
28+
}
29+
/** @implements {A} */
30+
declare class B implements A {
31+
method(): number;
32+
}
33+
/** @implements A */
34+
declare class B2 implements A {
35+
/** @return {string} */
36+
method(): string;
37+
}
38+
/** @implements {A} */
39+
declare class B3 implements A {
40+
}

tests/baselines/reference/jsdocImplements_class.symbols

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class A {
77
>method : Symbol(A.method, Decl(a.js, 0, 9))
88
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
99
}
10-
/** @implements A */
10+
/** @implements {A} */
1111
class B {
1212
>B : Symbol(B, Decl(a.js, 3, 1))
1313

@@ -24,7 +24,7 @@ class B2 {
2424
>method : Symbol(B2.method, Decl(a.js, 10, 11))
2525
}
2626

27-
/** @implements A */
27+
/** @implements {A} */
2828
class B3 {
2929
>B3 : Symbol(B3, Decl(a.js, 13, 1))
3030
}

tests/baselines/reference/jsdocImplements_class.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class A {
88
>new Error() : Error
99
>Error : ErrorConstructor
1010
}
11-
/** @implements A */
11+
/** @implements {A} */
1212
class B {
1313
>B : B
1414

@@ -27,7 +27,7 @@ class B2 {
2727
>"" : ""
2828
}
2929

30-
/** @implements A */
30+
/** @implements {A} */
3131
class B3 {
3232
>B3 : B3
3333
}

tests/baselines/reference/jsdocImplements_interface.errors.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
return 0;
1717
}
1818
}
19-
/** @implements A */
19+
/** @implements {A} */
2020
class B2 {
2121
mNumber() {
2222
~~~~~~~
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//// [tests/cases/conformance/jsdoc/jsdocImplements_interface.ts] ////
2+
3+
//// [defs.d.ts]
4+
interface A {
5+
mNumber(): number;
6+
}
7+
//// [a.js]
8+
/** @implements A */
9+
class B {
10+
mNumber() {
11+
return 0;
12+
}
13+
}
14+
/** @implements {A} */
15+
class B2 {
16+
mNumber() {
17+
return "";
18+
}
19+
}
20+
/** @implements A */
21+
class B3 {
22+
}
23+
24+
25+
26+
27+
//// [a.d.ts]
28+
/** @implements A */
29+
declare class B implements A {
30+
mNumber(): number;
31+
}
32+
/** @implements {A} */
33+
declare class B2 implements A {
34+
mNumber(): string;
35+
}
36+
/** @implements A */
37+
declare class B3 implements A {
38+
}

tests/baselines/reference/jsdocImplements_interface.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class B {
1616
return 0;
1717
}
1818
}
19-
/** @implements A */
19+
/** @implements {A} */
2020
class B2 {
2121
>B2 : Symbol(B2, Decl(a.js, 5, 1))
2222

tests/baselines/reference/jsdocImplements_interface.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class B {
1515
>0 : 0
1616
}
1717
}
18-
/** @implements A */
18+
/** @implements {A} */
1919
class B2 {
2020
>B2 : B2
2121

tests/baselines/reference/jsdocImplements_interface_multiple.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
}
1212
==== /a.js (1 errors) ====
1313
/**
14-
* @implements Drawable
14+
* @implements {Drawable}
1515
* @implements Sizable
1616
**/
1717
class Square {
@@ -24,7 +24,7 @@
2424
}
2525
/**
2626
* @implements Drawable
27-
* @implements Sizable
27+
* @implements {Sizable}
2828
**/
2929
class BadSquare {
3030
~~~~~~~~~
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//// [tests/cases/conformance/jsdoc/jsdocImplements_interface_multiple.ts] ////
2+
3+
//// [defs.d.ts]
4+
interface Drawable {
5+
draw(): number;
6+
}
7+
interface Sizable {
8+
size(): number;
9+
}
10+
//// [a.js]
11+
/**
12+
* @implements {Drawable}
13+
* @implements Sizable
14+
**/
15+
class Square {
16+
draw() {
17+
return 0;
18+
}
19+
size() {
20+
return 0;
21+
}
22+
}
23+
/**
24+
* @implements Drawable
25+
* @implements {Sizable}
26+
**/
27+
class BadSquare {
28+
size() {
29+
return 0;
30+
}
31+
}
32+
33+
34+
35+
//// [a.d.ts]
36+
/**
37+
* @implements {Drawable}
38+
* @implements Sizable
39+
**/
40+
declare class Square implements Drawable, Sizable {
41+
draw(): number;
42+
size(): number;
43+
}
44+
/**
45+
* @implements Drawable
46+
* @implements {Sizable}
47+
**/
48+
declare class BadSquare implements Drawable, Sizable {
49+
size(): number;
50+
}

tests/baselines/reference/jsdocImplements_interface_multiple.symbols

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface Sizable {
1313
}
1414
=== /a.js ===
1515
/**
16-
* @implements Drawable
16+
* @implements {Drawable}
1717
* @implements Sizable
1818
**/
1919
class Square {
@@ -32,7 +32,7 @@ class Square {
3232
}
3333
/**
3434
* @implements Drawable
35-
* @implements Sizable
35+
* @implements {Sizable}
3636
**/
3737
class BadSquare {
3838
>BadSquare : Symbol(BadSquare, Decl(a.js, 11, 1))

tests/baselines/reference/jsdocImplements_interface_multiple.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface Sizable {
99
}
1010
=== /a.js ===
1111
/**
12-
* @implements Drawable
12+
* @implements {Drawable}
1313
* @implements Sizable
1414
**/
1515
class Square {
@@ -30,7 +30,7 @@ class Square {
3030
}
3131
/**
3232
* @implements Drawable
33-
* @implements Sizable
33+
* @implements {Sizable}
3434
**/
3535
class BadSquare {
3636
>BadSquare : BadSquare
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [a.js]
2+
class A { constructor() { this.x = 0; } }
3+
/** @implements */
4+
class B {
5+
}
6+
7+
8+
9+
10+
//// [a.d.ts]
11+
declare class A {
12+
x: number;
13+
}
14+
/** @implements */
15+
declare class B {
16+
}

tests/baselines/reference/jsdocImplements_properties.errors.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
x = 10
1717
}
1818

19-
/** @implements A*/
19+
/** @implements {A}*/
2020
class B3 {
2121
constructor() { this.x = 10 }
2222
}

0 commit comments

Comments
 (0)