Always instantiate the extends clause, even in the presence of an error (#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
This commit is contained in:
Wesley Wigham 2017-12-01 21:09:06 -05:00 committed by GitHub
parent f6b1a1de59
commit 1045d95a44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 214 additions and 14 deletions

View file

@ -5817,7 +5817,7 @@ namespace ts {
for (const baseSig of baseSignatures) {
const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters);
const typeParamCount = length(baseSig.typeParameters);
if ((isJavaScript || typeArgCount >= minTypeArgumentCount) && typeArgCount <= typeParamCount) {
if (isJavaScript || (typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount)) {
const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig);
sig.typeParameters = classType.localTypeParameters;
sig.resolvedReturnType = classType;
@ -6718,7 +6718,7 @@ namespace ts {
const numTypeParameters = length(typeParameters);
if (numTypeParameters) {
const numTypeArguments = length(typeArguments);
if ((isJavaScriptImplicitAny || numTypeArguments >= minTypeArgumentCount) && numTypeArguments <= numTypeParameters) {
if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) {
if (!typeArguments) {
typeArguments = [];
}
@ -6737,6 +6737,7 @@ namespace ts {
}
typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : getDefaultTypeArgumentType(isJavaScriptImplicitAny);
}
typeArguments.length = typeParameters.length;
}
}
return typeArguments;
@ -7208,12 +7209,15 @@ namespace ts {
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments;
const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType);
error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length);
return unknownType;
if (!isJs) {
// TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments)
return unknownType;
}
}
// In a type reference, the outer type parameters of the referenced class or interface are automatically
// supplied as type arguments and the type reference only specifies arguments for the local type parameters
// of the class or interface.
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJsImplicitAny));
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs));
return createTypeReference(<GenericType>type, typeArguments);
}
if (node.typeArguments) {

View file

@ -1,17 +1,25 @@
/b.js(1,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
/b.js(3,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
/b.js(4,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
/b.js(8,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
==== /a.d.ts (0 errors) ====
declare class A<T> { x: T; }
==== /b.js (2 errors) ====
==== /b.js (3 errors) ====
class B extends A {}
~
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
new B().x;
/** @augments A */
~
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
class C { }
class C extends A { }
new C().x;
/** @augments A<number, number, number> */
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
class D extends A {}
new D().x;

View file

@ -10,7 +10,28 @@ class B extends A {}
>B : Symbol(B, Decl(b.js, 0, 0))
>A : Symbol(A, Decl(a.d.ts, 0, 0))
/** @augments A */
class C { }
>C : Symbol(C, Decl(b.js, 0, 20))
new B().x;
>new B().x : Symbol(A.x, Decl(a.d.ts, 0, 20))
>B : Symbol(B, Decl(b.js, 0, 0))
>x : Symbol(A.x, Decl(a.d.ts, 0, 20))
/** @augments A */
class C extends A { }
>C : Symbol(C, Decl(b.js, 1, 10))
>A : Symbol(A, Decl(a.d.ts, 0, 0))
new C().x;
>new C().x : Symbol(A.x, Decl(a.d.ts, 0, 20))
>C : Symbol(C, Decl(b.js, 1, 10))
>x : Symbol(A.x, Decl(a.d.ts, 0, 20))
/** @augments A<number, number, number> */
class D extends A {}
>D : Symbol(D, Decl(b.js, 5, 10))
>A : Symbol(A, Decl(a.d.ts, 0, 0))
new D().x;
>new D().x : Symbol(A.x, Decl(a.d.ts, 0, 20))
>D : Symbol(D, Decl(b.js, 5, 10))
>x : Symbol(A.x, Decl(a.d.ts, 0, 20))

View file

@ -8,9 +8,33 @@ declare class A<T> { x: T; }
=== /b.js ===
class B extends A {}
>B : B
>A : typeof A
>A : A<any>
new B().x;
>new B().x : any
>new B() : B
>B : typeof B
>x : any
/** @augments A */
class C { }
class C extends A { }
>C : C
>A : A<any>
new C().x;
>new C().x : any
>new C() : C
>C : typeof C
>x : any
/** @augments A<number, number, number> */
class D extends A {}
>D : D
>A : A<number>
new D().x;
>new D().x : number
>new D() : D
>D : typeof D
>x : number

View file

@ -0,0 +1,19 @@
tests/cases/compiler/index.js(3,21): error TS8026: Expected Foo<T> type arguments; provide these with an '@extends' tag.
==== tests/cases/compiler/somelib.d.ts (0 errors) ====
export declare class Foo<T> {
prop: T;
}
==== tests/cases/compiler/index.js (1 errors) ====
import {Foo} from "./somelib";
class MyFoo extends Foo {
~~~
!!! error TS8026: Expected Foo<T> type arguments; provide these with an '@extends' tag.
constructor() {
super();
this.prop.alpha = 12;
}
}

View file

@ -0,0 +1,40 @@
//// [tests/cases/compiler/jsNoImplicitAnyNoCascadingReferenceErrors.ts] ////
//// [somelib.d.ts]
export declare class Foo<T> {
prop: T;
}
//// [index.js]
import {Foo} from "./somelib";
class MyFoo extends Foo {
constructor() {
super();
this.prop.alpha = 12;
}
}
//// [index.js]
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var somelib_1 = require("./somelib");
var MyFoo = /** @class */ (function (_super) {
__extends(MyFoo, _super);
function MyFoo() {
var _this = _super.call(this) || this;
_this.prop.alpha = 12;
return _this;
}
return MyFoo;
}(somelib_1.Foo));

View file

@ -0,0 +1,28 @@
=== tests/cases/compiler/somelib.d.ts ===
export declare class Foo<T> {
>Foo : Symbol(Foo, Decl(somelib.d.ts, --, --))
>T : Symbol(T, Decl(somelib.d.ts, --, --))
prop: T;
>prop : Symbol(Foo.prop, Decl(somelib.d.ts, --, --))
>T : Symbol(T, Decl(somelib.d.ts, --, --))
}
=== tests/cases/compiler/index.js ===
import {Foo} from "./somelib";
>Foo : Symbol(Foo, Decl(index.js, 0, 8))
class MyFoo extends Foo {
>MyFoo : Symbol(MyFoo, Decl(index.js, 0, 30))
>Foo : Symbol(Foo, Decl(index.js, 0, 8))
constructor() {
super();
>super : Symbol(Foo, Decl(somelib.d.ts, --, --))
this.prop.alpha = 12;
>this.prop : Symbol(Foo.prop, Decl(somelib.d.ts, --, --))
>this : Symbol(MyFoo, Decl(index.js, 0, 30))
>prop : Symbol(Foo.prop, Decl(somelib.d.ts, --, --))
}
}

View file

@ -0,0 +1,33 @@
=== tests/cases/compiler/somelib.d.ts ===
export declare class Foo<T> {
>Foo : Foo<T>
>T : T
prop: T;
>prop : T
>T : T
}
=== tests/cases/compiler/index.js ===
import {Foo} from "./somelib";
>Foo : typeof Foo
class MyFoo extends Foo {
>MyFoo : MyFoo
>Foo : Foo<any>
constructor() {
super();
>super() : void
>super : typeof Foo
this.prop.alpha = 12;
>this.prop.alpha = 12 : 12
>this.prop.alpha : any
>this.prop : any
>this : this
>prop : any
>alpha : any
>12 : 12
}
}

View file

@ -8,6 +8,12 @@ declare class A<T> { x: T; }
// @Filename: /b.js
class B extends A {}
new B().x;
/** @augments A */
class C { }
class C extends A { }
new C().x;
/** @augments A<number, number, number> */
class D extends A {}
new D().x;

View file

@ -0,0 +1,17 @@
// @allowJs: true
// @checkJs: true
// @noImplicitAny: true
// @outDir: ./built
// @filename: somelib.d.ts
export declare class Foo<T> {
prop: T;
}
// @filename: index.js
import {Foo} from "./somelib";
class MyFoo extends Foo {
constructor() {
super();
this.prop.alpha = 12;
}
}