Skip to content

Commit 8b7d859

Browse files
author
Andy
authored
Make it a noImplicitAny error to fail to provide type arguments to a superclass via @Augments (microsoft#18778)
* Make it a noImplicitAny error to fail to provide type arguments to a superclass via @Augments * Don't recommend to add an @Augments tag if it already exists * Suggestions from code review * Shorten error message
1 parent d7be61a commit 8b7d859

File tree

6 files changed

+88
-14
lines changed

6 files changed

+88
-14
lines changed

src/compiler/checker.ts

+18-14
Original file line numberDiff line numberDiff line change
@@ -6420,11 +6420,11 @@ namespace ts {
64206420
* @param typeParameters The requested type parameters.
64216421
* @param minTypeArgumentCount The minimum number of required type arguments.
64226422
*/
6423-
function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScript: boolean) {
6423+
function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean) {
64246424
const numTypeParameters = length(typeParameters);
64256425
if (numTypeParameters) {
64266426
const numTypeArguments = length(typeArguments);
6427-
if ((isJavaScript || numTypeArguments >= minTypeArgumentCount) && numTypeArguments <= numTypeParameters) {
6427+
if ((isJavaScriptImplicitAny || numTypeArguments >= minTypeArgumentCount) && numTypeArguments <= numTypeParameters) {
64286428
if (!typeArguments) {
64296429
typeArguments = [];
64306430
}
@@ -6433,12 +6433,12 @@ namespace ts {
64336433
// If a type parameter does not have a default type, or if the default type
64346434
// is a forward reference, the empty object type is used.
64356435
for (let i = numTypeArguments; i < numTypeParameters; i++) {
6436-
typeArguments[i] = getDefaultTypeArgumentType(isJavaScript);
6436+
typeArguments[i] = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
64376437
}
64386438
for (let i = numTypeArguments; i < numTypeParameters; i++) {
64396439
const mapper = createTypeMapper(typeParameters, typeArguments);
64406440
const defaultType = getDefaultFromTypeParameter(typeParameters[i]);
6441-
typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : getDefaultTypeArgumentType(isJavaScript);
6441+
typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : getDefaultTypeArgumentType(isJavaScriptImplicitAny);
64426442
}
64436443
}
64446444
}
@@ -6874,21 +6874,25 @@ namespace ts {
68746874
if (typeParameters) {
68756875
const numTypeArguments = length(node.typeArguments);
68766876
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
6877-
const isJavascript = isInJavaScriptFile(node);
6878-
if (!isJavascript && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) {
6879-
error(node,
6880-
minTypeArgumentCount === typeParameters.length
6881-
? Diagnostics.Generic_type_0_requires_1_type_argument_s
6882-
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments,
6883-
typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType),
6884-
minTypeArgumentCount,
6885-
typeParameters.length);
6877+
const isJs = isInJavaScriptFile(node);
6878+
const isJsImplicitAny = !compilerOptions.noImplicitAny && isJs;
6879+
if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) {
6880+
const missingAugmentsTag = isJs && node.parent.kind !== SyntaxKind.JSDocAugmentsTag;
6881+
const diag = minTypeArgumentCount === typeParameters.length
6882+
? missingAugmentsTag
6883+
? Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag
6884+
: Diagnostics.Generic_type_0_requires_1_type_argument_s
6885+
: missingAugmentsTag
6886+
? Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag
6887+
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments;
6888+
const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType);
6889+
error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length);
68866890
return unknownType;
68876891
}
68886892
// In a type reference, the outer type parameters of the referenced class or interface are automatically
68896893
// supplied as type arguments and the type reference only specifies arguments for the local type parameters
68906894
// of the class or interface.
6891-
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJavascript));
6895+
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJsImplicitAny));
68926896
return createTypeReference(<GenericType>type, typeArguments);
68936897
}
68946898
if (node.typeArguments) {

src/compiler/diagnosticMessages.json

+8
Original file line numberDiff line numberDiff line change
@@ -3539,6 +3539,14 @@
35393539
"category": "Error",
35403540
"code": 8025
35413541
},
3542+
"Expected {0} type arguments; provide these with an '@extends' tag.": {
3543+
"category": "Error",
3544+
"code": 8026
3545+
},
3546+
"Expected {0}-{1} type arguments; provide these with an '@extends' tag.": {
3547+
"category": "Error",
3548+
"code": 8027
3549+
},
35423550
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
35433551
"category": "Error",
35443552
"code": 9002
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/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).
3+
4+
5+
==== /a.d.ts (0 errors) ====
6+
declare class A<T> { x: T; }
7+
8+
==== /b.js (2 errors) ====
9+
class B extends A {}
10+
~
11+
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
12+
13+
/** @augments A */
14+
~
15+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
16+
class C { }
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== /a.d.ts ===
2+
declare class A<T> { x: T; }
3+
>A : Symbol(A, Decl(a.d.ts, 0, 0))
4+
>T : Symbol(T, Decl(a.d.ts, 0, 16))
5+
>x : Symbol(A.x, Decl(a.d.ts, 0, 20))
6+
>T : Symbol(T, Decl(a.d.ts, 0, 16))
7+
8+
=== /b.js ===
9+
class B extends A {}
10+
>B : Symbol(B, Decl(b.js, 0, 0))
11+
>A : Symbol(A, Decl(a.d.ts, 0, 0))
12+
13+
/** @augments A */
14+
class C { }
15+
>C : Symbol(C, Decl(b.js, 0, 20))
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== /a.d.ts ===
2+
declare class A<T> { x: T; }
3+
>A : A<T>
4+
>T : T
5+
>x : T
6+
>T : T
7+
8+
=== /b.js ===
9+
class B extends A {}
10+
>B : B
11+
>A : typeof A
12+
13+
/** @augments A */
14+
class C { }
15+
>C : C
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @noEmit: true
4+
// @noImplicitAny: true
5+
6+
// @Filename: /a.d.ts
7+
declare class A<T> { x: T; }
8+
9+
// @Filename: /b.js
10+
class B extends A {}
11+
12+
/** @augments A */
13+
class C { }

0 commit comments

Comments
 (0)