Skip to content

Commit 136f728

Browse files
authored
Fix js declaration emit for inherited and this-typed inherited fields (#37970)
1 parent 6ea291a commit 136f728

7 files changed

+142
-6
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5459,7 +5459,7 @@ namespace ts {
54595459
function serializeReturnTypeForSignature(context: NodeBuilderContext, type: Type, signature: Signature, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) {
54605460
if (type !== errorType && context.enclosingDeclaration) {
54615461
const annotation = signature.declaration && getEffectiveReturnTypeNode(signature.declaration);
5462-
if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation && getTypeFromTypeNode(annotation) === type) {
5462+
if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation && instantiateType(getTypeFromTypeNode(annotation), signature.mapper) === type) {
54635463
const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled);
54645464
if (result) {
54655465
return result;
@@ -6211,7 +6211,7 @@ namespace ts {
62116211
...!length(baseTypes) ? [] : [createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))],
62126212
...!length(implementsTypes) ? [] : [createHeritageClause(SyntaxKind.ImplementsKeyword, map(implementsTypes, b => serializeBaseType(b, staticBaseType, localName)))]
62136213
];
6214-
const symbolProps = getPropertiesOfType(classType);
6214+
const symbolProps = getNonInterhitedProperties(classType, baseTypes, getPropertiesOfType(classType));
62156215
const publicSymbolProps = filter(symbolProps, s => {
62166216
// `valueDeclaration` could be undefined if inherited from
62176217
// a union/intersection base type, but inherited properties
@@ -33482,6 +33482,26 @@ namespace ts {
3348233482
}
3348333483
}
3348433484

33485+
function getNonInterhitedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) {
33486+
if (!length(baseTypes)) {
33487+
return properties;
33488+
}
33489+
const seen = createUnderscoreEscapedMap<Symbol>();
33490+
forEach(properties, p => { seen.set(p.escapedName, p); });
33491+
33492+
for (const base of baseTypes) {
33493+
const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType));
33494+
for (const prop of properties) {
33495+
const existing = seen.get(prop.escapedName);
33496+
if (existing && !isPropertyIdenticalTo(existing, prop)) {
33497+
seen.delete(prop.escapedName);
33498+
}
33499+
}
33500+
}
33501+
33502+
return arrayFrom(seen.values());
33503+
}
33504+
3348533505
function checkInheritedPropertiesAreIdentical(type: InterfaceType, typeNode: Node): boolean {
3348633506
const baseTypes = getBaseTypes(type);
3348733507
if (baseTypes.length < 2) {

tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ export const updateIfChanged = <T>(t: T) => {
3838
>newU : U
3939

4040
return Object.assign(
41-
>Object.assign( <K extends Key<U>>(key: K) => reduce<Value<K, U>>(u[key as keyof U] as Value<K, U>, (v: Value<K, U>) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }), { map: (updater: (u: U) => U) => set(updater(u)), set }) : (<K extends keyof U>(key: K) => (<K extends keyof U[K]>(key: K) => (<K extends keyof U[K][K]>(key: K) => (<K extends keyof U[K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K][K]>(key: K) => any & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K]) => U[K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K]) => U[K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K]) => U[K][K][K][K]) => T; set: (newU: U[K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K]) => U[K][K][K]) => T; set: (newU: U[K][K][K]) => T; }) & { map: (updater: (u: U[K][K]) => U[K][K]) => T; set: (newU: U[K][K]) => T; }) & { map: (updater: (u: U[K]) => U[K]) => T; set: (newU: U[K]) => T; }) & { map: (updater: (u: U) => U) => T; set: (newU: U) => T; }
41+
>Object.assign( <K extends Key<U>>(key: K) => reduce<Value<K, U>>(u[key as keyof U] as Value<K, U>, (v: Value<K, U>) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }), { map: (updater: (u: U) => U) => set(updater(u)), set }) : (<K extends keyof U>(key: K) => (<K extends keyof U[K]>(key: K) => (<K extends keyof U[K][K]>(key: K) => (<K extends keyof U[K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K][K]>(key: K) => any & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K]) => U) => T; set: (newU: U[K][K][K]) => T; }) & { map: (updater: (u: U[K][K]) => U) => T; set: (newU: U[K][K]) => T; }) & { map: (updater: (u: U[K]) => U) => T; set: (newU: U[K]) => T; }) & { map: (updater: (u: U) => U) => T; set: (newU: U) => T; }
4242
>Object.assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
4343
>Object : ObjectConstructor
4444
>assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
4545

4646
<K extends Key<U>>(key: K) =>
47-
><K extends Key<U>>(key: K) => reduce<Value<K, U>>(u[key as keyof U] as Value<K, U>, (v: Value<K, U>) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }) : <K extends keyof U>(key: K) => (<K extends keyof U[K]>(key: K) => (<K extends keyof U[K][K]>(key: K) => (<K extends keyof U[K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K][K]>(key: K) => any & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K]) => U[K][K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K]) => U[K][K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K]) => U[K][K][K][K][K]) => T; set: (newU: U[K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K]) => U[K][K][K][K]) => T; set: (newU: U[K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K]) => U[K][K][K]) => T; set: (newU: U[K][K][K]) => T; }) & { map: (updater: (u: U[K][K]) => U[K][K]) => T; set: (newU: U[K][K]) => T; }) & { map: (updater: (u: U[K]) => U[K]) => T; set: (newU: U[K]) => T; }
47+
><K extends Key<U>>(key: K) => reduce<Value<K, U>>(u[key as keyof U] as Value<K, U>, (v: Value<K, U>) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }) : <K extends keyof U>(key: K) => (<K extends keyof U[K]>(key: K) => (<K extends keyof U[K][K]>(key: K) => (<K extends keyof U[K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K]>(key: K) => (<K extends keyof U[K][K][K][K][K][K][K][K][K][K]>(key: K) => any & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K][K]) => U) => T; set: (newU: U[K][K][K][K]) => T; }) & { map: (updater: (u: U[K][K][K]) => U) => T; set: (newU: U[K][K][K]) => T; }) & { map: (updater: (u: U[K][K]) => U) => T; set: (newU: U[K][K]) => T; }) & { map: (updater: (u: U[K]) => U) => T; set: (newU: U[K]) => T; }
4848
>key : K
4949

5050
reduce<Value<K, U>>(u[key as keyof U] as Value<K, U>, (v: Value<K, U>) => {

tests/baselines/reference/jsDeclarationsInterfaces.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ export interface B {
135135
export interface C<T_1, U_1> {
136136
new (): string;
137137
new (x: T_1): U_1;
138-
new <Q_4>(x: Q_4): T_1 & Q_4;
138+
new <Q_6>(x: Q_6): T_1 & Q_6;
139139
(): number;
140140
(x: T_1): U_1;
141-
<Q_3>(x: Q_3): T_1 & Q_3;
141+
<Q_4>(x: Q_4): T_1 & Q_4;
142142
field: T_1 & U_1;
143143
optionalField?: T_1;
144144
readonly readonlyField: T_1 & U_1;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//// [index.js]
2+
export class A {
3+
/** @returns {this} */
4+
method() {
5+
return this;
6+
}
7+
}
8+
export default class Base extends A {
9+
// This method is required to reproduce #35932
10+
verify() { }
11+
}
12+
13+
//// [index.js]
14+
"use strict";
15+
var __extends = (this && this.__extends) || (function () {
16+
var extendStatics = function (d, b) {
17+
extendStatics = Object.setPrototypeOf ||
18+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
19+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
20+
return extendStatics(d, b);
21+
};
22+
return function (d, b) {
23+
extendStatics(d, b);
24+
function __() { this.constructor = d; }
25+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
26+
};
27+
})();
28+
exports.__esModule = true;
29+
exports.A = void 0;
30+
var A = /** @class */ (function () {
31+
function A() {
32+
}
33+
/** @returns {this} */
34+
A.prototype.method = function () {
35+
return this;
36+
};
37+
return A;
38+
}());
39+
exports.A = A;
40+
var Base = /** @class */ (function (_super) {
41+
__extends(Base, _super);
42+
function Base() {
43+
return _super !== null && _super.apply(this, arguments) || this;
44+
}
45+
// This method is required to reproduce #35932
46+
Base.prototype.verify = function () { };
47+
return Base;
48+
}(A));
49+
exports["default"] = Base;
50+
51+
52+
//// [index.d.ts]
53+
export class A {
54+
/** @returns {this} */
55+
method(): this;
56+
}
57+
export default class Base extends A {
58+
verify(): void;
59+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/jsdoc/declarations/index.js ===
2+
export class A {
3+
>A : Symbol(A, Decl(index.js, 0, 0))
4+
5+
/** @returns {this} */
6+
method() {
7+
>method : Symbol(A.method, Decl(index.js, 0, 16))
8+
9+
return this;
10+
>this : Symbol(A, Decl(index.js, 0, 0))
11+
}
12+
}
13+
export default class Base extends A {
14+
>Base : Symbol(Base, Decl(index.js, 5, 1))
15+
>A : Symbol(A, Decl(index.js, 0, 0))
16+
17+
// This method is required to reproduce #35932
18+
verify() { }
19+
>verify : Symbol(Base.verify, Decl(index.js, 6, 37))
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/jsdoc/declarations/index.js ===
2+
export class A {
3+
>A : A
4+
5+
/** @returns {this} */
6+
method() {
7+
>method : () => this
8+
9+
return this;
10+
>this : this
11+
}
12+
}
13+
export default class Base extends A {
14+
>Base : Base
15+
>A : A
16+
17+
// This method is required to reproduce #35932
18+
verify() { }
19+
>verify : () => void
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @outDir: /out
4+
// @lib: es6
5+
// @declaration: true
6+
// @filename: index.js
7+
8+
export class A {
9+
/** @returns {this} */
10+
method() {
11+
return this;
12+
}
13+
}
14+
export default class Base extends A {
15+
// This method is required to reproduce #35932
16+
verify() { }
17+
}

0 commit comments

Comments
 (0)