Skip to content

Commit 1045d95

Browse files
authored
Always instantiate the extends clause, even in the presence of an error (microsoft#20232)
* Still instantiate the extends clause even when theres a noimplicitany error in js * Only be permissive for JS * In JS, instantiate classes even when they have too many type arguments, instead of returning unknownType
1 parent f6b1a1d commit 1045d95

10 files changed

Lines changed: 213 additions & 13 deletions

src/compiler/checker.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5817,7 +5817,7 @@ namespace ts {
58175817
for (const baseSig of baseSignatures) {
58185818
const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters);
58195819
const typeParamCount = length(baseSig.typeParameters);
5820-
if ((isJavaScript || typeArgCount >= minTypeArgumentCount) && typeArgCount <= typeParamCount) {
5820+
if (isJavaScript || (typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount)) {
58215821
const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig);
58225822
sig.typeParameters = classType.localTypeParameters;
58235823
sig.resolvedReturnType = classType;
@@ -6718,7 +6718,7 @@ namespace ts {
67186718
const numTypeParameters = length(typeParameters);
67196719
if (numTypeParameters) {
67206720
const numTypeArguments = length(typeArguments);
6721-
if ((isJavaScriptImplicitAny || numTypeArguments >= minTypeArgumentCount) && numTypeArguments <= numTypeParameters) {
6721+
if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) {
67226722
if (!typeArguments) {
67236723
typeArguments = [];
67246724
}
@@ -6737,6 +6737,7 @@ namespace ts {
67376737
}
67386738
typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : getDefaultTypeArgumentType(isJavaScriptImplicitAny);
67396739
}
6740+
typeArguments.length = typeParameters.length;
67406741
}
67416742
}
67426743
return typeArguments;
@@ -7208,12 +7209,15 @@ namespace ts {
72087209
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments;
72097210
const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType);
72107211
error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length);
7211-
return unknownType;
7212+
if (!isJs) {
7213+
// TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments)
7214+
return unknownType;
7215+
}
72127216
}
72137217
// In a type reference, the outer type parameters of the referenced class or interface are automatically
72147218
// supplied as type arguments and the type reference only specifies arguments for the local type parameters
72157219
// of the class or interface.
7216-
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJsImplicitAny));
7220+
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs));
72177221
return createTypeReference(<GenericType>type, typeArguments);
72187222
}
72197223
if (node.typeArguments) {
Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
/b.js(1,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
2-
/b.js(3,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
2+
/b.js(4,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
3+
/b.js(8,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
34

45

56
==== /a.d.ts (0 errors) ====
67
declare class A<T> { x: T; }
78

8-
==== /b.js (2 errors) ====
9+
==== /b.js (3 errors) ====
910
class B extends A {}
1011
~
1112
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
13+
new B().x;
1214

1315
/** @augments A */
1416
~
1517
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
16-
class C { }
17-
18+
class C extends A { }
19+
new C().x;
20+
21+
/** @augments A<number, number, number> */
22+
~~~~~~~~~~~~~~~~~~~~~~~~~
23+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
24+
class D extends A {}
25+
new D().x;

tests/baselines/reference/jsExtendsImplicitAny.symbols

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,28 @@ class B extends A {}
1010
>B : Symbol(B, Decl(b.js, 0, 0))
1111
>A : Symbol(A, Decl(a.d.ts, 0, 0))
1212

13+
new B().x;
14+
>new B().x : Symbol(A.x, Decl(a.d.ts, 0, 20))
15+
>B : Symbol(B, Decl(b.js, 0, 0))
16+
>x : Symbol(A.x, Decl(a.d.ts, 0, 20))
17+
1318
/** @augments A */
14-
class C { }
15-
>C : Symbol(C, Decl(b.js, 0, 20))
19+
class C extends A { }
20+
>C : Symbol(C, Decl(b.js, 1, 10))
21+
>A : Symbol(A, Decl(a.d.ts, 0, 0))
22+
23+
new C().x;
24+
>new C().x : Symbol(A.x, Decl(a.d.ts, 0, 20))
25+
>C : Symbol(C, Decl(b.js, 1, 10))
26+
>x : Symbol(A.x, Decl(a.d.ts, 0, 20))
27+
28+
/** @augments A<number, number, number> */
29+
class D extends A {}
30+
>D : Symbol(D, Decl(b.js, 5, 10))
31+
>A : Symbol(A, Decl(a.d.ts, 0, 0))
32+
33+
new D().x;
34+
>new D().x : Symbol(A.x, Decl(a.d.ts, 0, 20))
35+
>D : Symbol(D, Decl(b.js, 5, 10))
36+
>x : Symbol(A.x, Decl(a.d.ts, 0, 20))
1637

tests/baselines/reference/jsExtendsImplicitAny.types

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,33 @@ declare class A<T> { x: T; }
88
=== /b.js ===
99
class B extends A {}
1010
>B : B
11-
>A : typeof A
11+
>A : A<any>
12+
13+
new B().x;
14+
>new B().x : any
15+
>new B() : B
16+
>B : typeof B
17+
>x : any
1218

1319
/** @augments A */
14-
class C { }
20+
class C extends A { }
1521
>C : C
22+
>A : A<any>
23+
24+
new C().x;
25+
>new C().x : any
26+
>new C() : C
27+
>C : typeof C
28+
>x : any
29+
30+
/** @augments A<number, number, number> */
31+
class D extends A {}
32+
>D : D
33+
>A : A<number>
34+
35+
new D().x;
36+
>new D().x : number
37+
>new D() : D
38+
>D : typeof D
39+
>x : number
1640

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
tests/cases/compiler/index.js(3,21): error TS8026: Expected Foo<T> type arguments; provide these with an '@extends' tag.
2+
3+
4+
==== tests/cases/compiler/somelib.d.ts (0 errors) ====
5+
export declare class Foo<T> {
6+
prop: T;
7+
}
8+
==== tests/cases/compiler/index.js (1 errors) ====
9+
import {Foo} from "./somelib";
10+
11+
class MyFoo extends Foo {
12+
~~~
13+
!!! error TS8026: Expected Foo<T> type arguments; provide these with an '@extends' tag.
14+
constructor() {
15+
super();
16+
this.prop.alpha = 12;
17+
}
18+
}
19+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/compiler/jsNoImplicitAnyNoCascadingReferenceErrors.ts] ////
2+
3+
//// [somelib.d.ts]
4+
export declare class Foo<T> {
5+
prop: T;
6+
}
7+
//// [index.js]
8+
import {Foo} from "./somelib";
9+
10+
class MyFoo extends Foo {
11+
constructor() {
12+
super();
13+
this.prop.alpha = 12;
14+
}
15+
}
16+
17+
18+
//// [index.js]
19+
"use strict";
20+
var __extends = (this && this.__extends) || (function () {
21+
var extendStatics = Object.setPrototypeOf ||
22+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
23+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
24+
return function (d, b) {
25+
extendStatics(d, b);
26+
function __() { this.constructor = d; }
27+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
28+
};
29+
})();
30+
exports.__esModule = true;
31+
var somelib_1 = require("./somelib");
32+
var MyFoo = /** @class */ (function (_super) {
33+
__extends(MyFoo, _super);
34+
function MyFoo() {
35+
var _this = _super.call(this) || this;
36+
_this.prop.alpha = 12;
37+
return _this;
38+
}
39+
return MyFoo;
40+
}(somelib_1.Foo));
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== tests/cases/compiler/somelib.d.ts ===
2+
export declare class Foo<T> {
3+
>Foo : Symbol(Foo, Decl(somelib.d.ts, --, --))
4+
>T : Symbol(T, Decl(somelib.d.ts, --, --))
5+
6+
prop: T;
7+
>prop : Symbol(Foo.prop, Decl(somelib.d.ts, --, --))
8+
>T : Symbol(T, Decl(somelib.d.ts, --, --))
9+
}
10+
=== tests/cases/compiler/index.js ===
11+
import {Foo} from "./somelib";
12+
>Foo : Symbol(Foo, Decl(index.js, 0, 8))
13+
14+
class MyFoo extends Foo {
15+
>MyFoo : Symbol(MyFoo, Decl(index.js, 0, 30))
16+
>Foo : Symbol(Foo, Decl(index.js, 0, 8))
17+
18+
constructor() {
19+
super();
20+
>super : Symbol(Foo, Decl(somelib.d.ts, --, --))
21+
22+
this.prop.alpha = 12;
23+
>this.prop : Symbol(Foo.prop, Decl(somelib.d.ts, --, --))
24+
>this : Symbol(MyFoo, Decl(index.js, 0, 30))
25+
>prop : Symbol(Foo.prop, Decl(somelib.d.ts, --, --))
26+
}
27+
}
28+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/somelib.d.ts ===
2+
export declare class Foo<T> {
3+
>Foo : Foo<T>
4+
>T : T
5+
6+
prop: T;
7+
>prop : T
8+
>T : T
9+
}
10+
=== tests/cases/compiler/index.js ===
11+
import {Foo} from "./somelib";
12+
>Foo : typeof Foo
13+
14+
class MyFoo extends Foo {
15+
>MyFoo : MyFoo
16+
>Foo : Foo<any>
17+
18+
constructor() {
19+
super();
20+
>super() : void
21+
>super : typeof Foo
22+
23+
this.prop.alpha = 12;
24+
>this.prop.alpha = 12 : 12
25+
>this.prop.alpha : any
26+
>this.prop : any
27+
>this : this
28+
>prop : any
29+
>alpha : any
30+
>12 : 12
31+
}
32+
}
33+

tests/cases/compiler/jsExtendsImplicitAny.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ declare class A<T> { x: T; }
88

99
// @Filename: /b.js
1010
class B extends A {}
11+
new B().x;
1112

1213
/** @augments A */
13-
class C { }
14+
class C extends A { }
15+
new C().x;
16+
17+
/** @augments A<number, number, number> */
18+
class D extends A {}
19+
new D().x;
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+
// @noImplicitAny: true
4+
// @outDir: ./built
5+
// @filename: somelib.d.ts
6+
export declare class Foo<T> {
7+
prop: T;
8+
}
9+
// @filename: index.js
10+
import {Foo} from "./somelib";
11+
12+
class MyFoo extends Foo {
13+
constructor() {
14+
super();
15+
this.prop.alpha = 12;
16+
}
17+
}

0 commit comments

Comments
 (0)