diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 103200600b219..f831a157483c6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7663,8 +7663,10 @@ namespace ts { // Map an unsatisfied type parameter with a default type. // If a type parameter does not have a default type, or if the default type // is a forward reference, the empty object type is used. + const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny); + const circularityMapper = createTypeMapper(typeParameters!, map(typeParameters!, () => baseDefaultType)); for (let i = numTypeArguments; i < numTypeParameters; i++) { - result[i] = getConstraintFromTypeParameter(typeParameters![i]) || getDefaultTypeArgumentType(isJavaScriptImplicitAny); + result[i] = instantiateType(getConstraintFromTypeParameter(typeParameters![i]) || baseDefaultType, circularityMapper); } for (let i = numTypeArguments; i < numTypeParameters; i++) { const mapper = createTypeMapper(typeParameters!, result); @@ -7672,7 +7674,7 @@ namespace ts { if (isJavaScriptImplicitAny && defaultType && isTypeIdenticalTo(defaultType, emptyObjectType)) { defaultType = anyType; } - result[i] = defaultType ? instantiateType(defaultType, mapper) : getDefaultTypeArgumentType(isJavaScriptImplicitAny); + result[i] = defaultType ? instantiateType(defaultType, mapper) : baseDefaultType; } result.length = typeParameters!.length; return result; diff --git a/tests/baselines/reference/subclassThisTypeAssignable.js b/tests/baselines/reference/subclassThisTypeAssignable.js new file mode 100644 index 0000000000000..b82e4462a0514 --- /dev/null +++ b/tests/baselines/reference/subclassThisTypeAssignable.js @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/subclassThisTypeAssignable.ts] //// + +//// [tile1.ts] +interface Lifecycle { + oninit?(vnode: Vnode): number; + [_: number]: any; +} + +interface Vnode = Lifecycle> { + tag: Component; +} + +interface Component { + view(this: State, vnode: Vnode): number; +} + +interface ClassComponent extends Lifecycle> { + oninit?(vnode: Vnode): number; + view(vnode: Vnode): number; +} + +interface MyAttrs { id: number } +class C implements ClassComponent { + view(v: Vnode) { return 0; } +} + +const test8: ClassComponent = new C(); +//// [file1.js] +/** @type {ClassComponent} */ +const test9 = new C(); + + +//// [tile1.js] +var C = /** @class */ (function () { + function C() { + } + C.prototype.view = function (v) { return 0; }; + return C; +}()); +var test8 = new C(); +//// [file1.js] +/** @type {ClassComponent} */ +var test9 = new C(); diff --git a/tests/baselines/reference/subclassThisTypeAssignable.symbols b/tests/baselines/reference/subclassThisTypeAssignable.symbols new file mode 100644 index 0000000000000..8cfc25b28a66c --- /dev/null +++ b/tests/baselines/reference/subclassThisTypeAssignable.symbols @@ -0,0 +1,98 @@ +=== tests/cases/compiler/tile1.ts === +interface Lifecycle { +>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 0, 20)) +>State : Symbol(State, Decl(tile1.ts, 0, 26)) + + oninit?(vnode: Vnode): number; +>oninit : Symbol(Lifecycle.oninit, Decl(tile1.ts, 0, 35)) +>vnode : Symbol(vnode, Decl(tile1.ts, 1, 9)) +>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 0, 20)) +>State : Symbol(State, Decl(tile1.ts, 0, 26)) + + [_: number]: any; +>_ : Symbol(_, Decl(tile1.ts, 2, 2)) +} + +interface Vnode = Lifecycle> { +>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 5, 16)) +>State : Symbol(State, Decl(tile1.ts, 5, 22)) +>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 5, 16)) +>State : Symbol(State, Decl(tile1.ts, 5, 22)) +>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 5, 16)) +>State : Symbol(State, Decl(tile1.ts, 5, 22)) + + tag: Component; +>tag : Symbol(Vnode.tag, Decl(tile1.ts, 5, 89)) +>Component : Symbol(Component, Decl(tile1.ts, 7, 1)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 5, 16)) +>State : Symbol(State, Decl(tile1.ts, 5, 22)) +} + +interface Component { +>Component : Symbol(Component, Decl(tile1.ts, 7, 1)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 9, 20)) +>State : Symbol(State, Decl(tile1.ts, 9, 26)) + + view(this: State, vnode: Vnode): number; +>view : Symbol(Component.view, Decl(tile1.ts, 9, 35)) +>this : Symbol(this, Decl(tile1.ts, 10, 6)) +>State : Symbol(State, Decl(tile1.ts, 9, 26)) +>vnode : Symbol(vnode, Decl(tile1.ts, 10, 18)) +>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1)) +>Attrs : Symbol(Attrs, Decl(tile1.ts, 9, 20)) +>State : Symbol(State, Decl(tile1.ts, 9, 26)) +} + +interface ClassComponent extends Lifecycle> { +>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1)) +>A : Symbol(A, Decl(tile1.ts, 13, 25)) +>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0)) +>A : Symbol(A, Decl(tile1.ts, 13, 25)) +>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1)) +>A : Symbol(A, Decl(tile1.ts, 13, 25)) + + oninit?(vnode: Vnode): number; +>oninit : Symbol(ClassComponent.oninit, Decl(tile1.ts, 13, 69)) +>vnode : Symbol(vnode, Decl(tile1.ts, 14, 9)) +>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1)) +>A : Symbol(A, Decl(tile1.ts, 13, 25)) + + view(vnode: Vnode): number; +>view : Symbol(ClassComponent.view, Decl(tile1.ts, 14, 40)) +>vnode : Symbol(vnode, Decl(tile1.ts, 15, 6)) +>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1)) +>A : Symbol(A, Decl(tile1.ts, 13, 25)) +} + +interface MyAttrs { id: number } +>MyAttrs : Symbol(MyAttrs, Decl(tile1.ts, 16, 1)) +>id : Symbol(MyAttrs.id, Decl(tile1.ts, 18, 19)) + +class C implements ClassComponent { +>C : Symbol(C, Decl(tile1.ts, 18, 32)) +>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1)) +>MyAttrs : Symbol(MyAttrs, Decl(tile1.ts, 16, 1)) + + view(v: Vnode) { return 0; } +>view : Symbol(C.view, Decl(tile1.ts, 19, 44)) +>v : Symbol(v, Decl(tile1.ts, 20, 6)) +>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1)) +>MyAttrs : Symbol(MyAttrs, Decl(tile1.ts, 16, 1)) +} + +const test8: ClassComponent = new C(); +>test8 : Symbol(test8, Decl(tile1.ts, 23, 5)) +>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1)) +>C : Symbol(C, Decl(tile1.ts, 18, 32)) + +=== tests/cases/compiler/file1.js === +/** @type {ClassComponent} */ +const test9 = new C(); +>test9 : Symbol(test9, Decl(file1.js, 1, 5)) +>C : Symbol(C, Decl(tile1.ts, 18, 32)) + diff --git a/tests/baselines/reference/subclassThisTypeAssignable.types b/tests/baselines/reference/subclassThisTypeAssignable.types new file mode 100644 index 0000000000000..711b0056277f8 --- /dev/null +++ b/tests/baselines/reference/subclassThisTypeAssignable.types @@ -0,0 +1,56 @@ +=== tests/cases/compiler/tile1.ts === +interface Lifecycle { + oninit?(vnode: Vnode): number; +>oninit : (vnode: Vnode) => number +>vnode : Vnode + + [_: number]: any; +>_ : number +} + +interface Vnode = Lifecycle> { + tag: Component; +>tag : Component +} + +interface Component { + view(this: State, vnode: Vnode): number; +>view : (this: State, vnode: Vnode) => number +>this : State +>vnode : Vnode +} + +interface ClassComponent extends Lifecycle> { + oninit?(vnode: Vnode): number; +>oninit : (vnode: Vnode) => number +>vnode : Vnode + + view(vnode: Vnode): number; +>view : (vnode: Vnode) => number +>vnode : Vnode +} + +interface MyAttrs { id: number } +>id : number + +class C implements ClassComponent { +>C : C + + view(v: Vnode) { return 0; } +>view : (v: Vnode>>) => number +>v : Vnode>> +>0 : 0 +} + +const test8: ClassComponent = new C(); +>test8 : ClassComponent +>new C() : C +>C : typeof C + +=== tests/cases/compiler/file1.js === +/** @type {ClassComponent} */ +const test9 = new C(); +>test9 : ClassComponent +>new C() : C +>C : typeof C + diff --git a/tests/cases/compiler/subclassThisTypeAssignable.ts b/tests/cases/compiler/subclassThisTypeAssignable.ts new file mode 100644 index 0000000000000..a582fd0f4c30b --- /dev/null +++ b/tests/cases/compiler/subclassThisTypeAssignable.ts @@ -0,0 +1,31 @@ +// @allowJs: true +// @checkJs: true +// @outDir: ./out +// @filename: tile1.ts +interface Lifecycle { + oninit?(vnode: Vnode): number; + [_: number]: any; +} + +interface Vnode = Lifecycle> { + tag: Component; +} + +interface Component { + view(this: State, vnode: Vnode): number; +} + +interface ClassComponent extends Lifecycle> { + oninit?(vnode: Vnode): number; + view(vnode: Vnode): number; +} + +interface MyAttrs { id: number } +class C implements ClassComponent { + view(v: Vnode) { return 0; } +} + +const test8: ClassComponent = new C(); +// @filename: file1.js +/** @type {ClassComponent} */ +const test9 = new C();