Skip to content

Commit 62e8881

Browse files
authored
Merge pull request #14907 from Microsoft/jsGenericDefaultsAny
Default to 'any' for unsupplied generics in JavaScript
2 parents 711f62f + ed1d5f4 commit 62e8881

File tree

4 files changed

+579
-16
lines changed

4 files changed

+579
-16
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4576,14 +4576,15 @@ namespace ts {
45764576
return getClassExtendsHeritageClauseElement(<ClassLikeDeclaration>type.symbol.valueDeclaration);
45774577
}
45784578

4579-
function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: TypeNode[]): Signature[] {
4579+
function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: TypeNode[], location: Node): Signature[] {
45804580
const typeArgCount = length(typeArgumentNodes);
4581+
const isJavaScript = isInJavaScriptFile(location);
45814582
return filter(getSignaturesOfType(type, SignatureKind.Construct),
4582-
sig => typeArgCount >= getMinTypeArgumentCount(sig.typeParameters) && typeArgCount <= length(sig.typeParameters));
4583+
sig => (isJavaScript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters));
45834584
}
45844585

4585-
function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: TypeNode[]): Signature[] {
4586-
let signatures = getConstructorsForTypeArguments(type, typeArgumentNodes);
4586+
function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: TypeNode[], location: Node): Signature[] {
4587+
let signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location);
45874588
if (typeArgumentNodes) {
45884589
const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode);
45894590
signatures = map(signatures, sig => getSignatureInstantiation(sig, typeArguments));
@@ -4666,7 +4667,7 @@ namespace ts {
46664667
// The class derives from a "class-like" constructor function, check that we have at least one construct signature
46674668
// with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere
46684669
// we check that all instantiated signatures return the same type.
4669-
const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments);
4670+
const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments, baseTypeNode);
46704671
if (!constructors.length) {
46714672
error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments);
46724673
return;
@@ -5176,14 +5177,15 @@ namespace ts {
51765177
return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false)];
51775178
}
51785179
const baseTypeNode = getBaseTypeNodeOfClass(classType);
5180+
const isJavaScript = isInJavaScriptFile(baseTypeNode);
51795181
const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode);
51805182
const typeArgCount = length(typeArguments);
51815183
const result: Signature[] = [];
51825184
for (const baseSig of baseSignatures) {
51835185
const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters);
51845186
const typeParamCount = length(baseSig.typeParameters);
5185-
if (typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount) {
5186-
const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount)) : cloneSignature(baseSig);
5187+
if ((isJavaScript || typeArgCount >= minTypeArgumentCount) && typeArgCount <= typeParamCount) {
5188+
const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, baseTypeNode)) : cloneSignature(baseSig);
51875189
sig.typeParameters = classType.localTypeParameters;
51885190
sig.resolvedReturnType = classType;
51895191
result.push(sig);
@@ -6016,11 +6018,12 @@ namespace ts {
60166018
* @param typeParameters The requested type parameters.
60176019
* @param minTypeArgumentCount The minimum number of required type arguments.
60186020
*/
6019-
function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number) {
6021+
function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, location?: Node) {
60206022
const numTypeParameters = length(typeParameters);
60216023
if (numTypeParameters) {
60226024
const numTypeArguments = length(typeArguments);
6023-
if (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters) {
6025+
const isJavaScript = isInJavaScriptFile(location);
6026+
if ((isJavaScript || numTypeArguments >= minTypeArgumentCount) && numTypeArguments <= numTypeParameters) {
60246027
if (!typeArguments) {
60256028
typeArguments = [];
60266029
}
@@ -6029,12 +6032,12 @@ namespace ts {
60296032
// If a type parameter does not have a default type, or if the default type
60306033
// is a forward reference, the empty object type is used.
60316034
for (let i = numTypeArguments; i < numTypeParameters; i++) {
6032-
typeArguments[i] = emptyObjectType;
6035+
typeArguments[i] = isJavaScript ? anyType : emptyObjectType;
60336036
}
60346037
for (let i = numTypeArguments; i < numTypeParameters; i++) {
60356038
const mapper = createTypeMapper(typeParameters, typeArguments);
60366039
const defaultType = getDefaultFromTypeParameter(typeParameters[i]);
6037-
typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : emptyObjectType;
6040+
typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : isJavaScript ? anyType : emptyObjectType;
60386041
}
60396042
}
60406043
}
@@ -6408,7 +6411,7 @@ namespace ts {
64086411
if (typeParameters) {
64096412
const numTypeArguments = length(node.typeArguments);
64106413
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
6411-
if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) {
6414+
if (!isInJavaScriptFile(node) && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) {
64126415
error(node,
64136416
minTypeArgumentCount === typeParameters.length
64146417
? Diagnostics.Generic_type_0_requires_1_type_argument_s
@@ -6421,7 +6424,7 @@ namespace ts {
64216424
// In a type reference, the outer type parameters of the referenced class or interface are automatically
64226425
// supplied as type arguments and the type reference only specifies arguments for the local type parameters
64236426
// of the class or interface.
6424-
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(map(node.typeArguments, getTypeFromTypeNode), typeParameters, minTypeArgumentCount));
6427+
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(map(node.typeArguments, getTypeFromTypeNode), typeParameters, minTypeArgumentCount, node));
64256428
return createTypeReference(<GenericType>type, typeArguments);
64266429
}
64276430
if (node.typeArguments) {
@@ -15066,7 +15069,7 @@ namespace ts {
1506615069
// with the type arguments specified in the extends clause.
1506715070
const baseTypeNode = getClassExtendsHeritageClauseElement(getContainingClass(node));
1506815071
if (baseTypeNode) {
15069-
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments);
15072+
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
1507015073
return resolveCall(node, baseConstructors, candidatesOutArray);
1507115074
}
1507215075
}
@@ -20180,7 +20183,7 @@ namespace ts {
2018020183
checkSourceElement(baseTypeNode.expression);
2018120184
if (baseTypeNode.typeArguments) {
2018220185
forEach(baseTypeNode.typeArguments, checkSourceElement);
20183-
for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments)) {
20186+
for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) {
2018420187
if (!checkTypeArgumentConstraints(constructor.typeParameters, baseTypeNode.typeArguments)) {
2018520188
break;
2018620189
}
@@ -20198,7 +20201,7 @@ namespace ts {
2019820201
// that all instantiated base constructor signatures return the same type. We can simply compare the type
2019920202
// references (as opposed to checking the structure of the types) because elsewhere we have already checked
2020020203
// that the base type is a class or interface type (and not, for example, an anonymous object type).
20201-
const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments);
20204+
const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode);
2020220205
if (forEach(constructors, sig => getReturnTypeOfSignature(sig) !== baseType)) {
2020320206
error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type);
2020420207
}
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
=== tests/cases/compiler/decls.d.ts ===
2+
declare function f0<T>(x?: T): T;
3+
>f0 : Symbol(f0, Decl(decls.d.ts, 0, 0))
4+
>T : Symbol(T, Decl(decls.d.ts, 0, 20))
5+
>x : Symbol(x, Decl(decls.d.ts, 0, 23))
6+
>T : Symbol(T, Decl(decls.d.ts, 0, 20))
7+
>T : Symbol(T, Decl(decls.d.ts, 0, 20))
8+
9+
declare function f1<T, U = number>(x?: T): [T, U];
10+
>f1 : Symbol(f1, Decl(decls.d.ts, 0, 33))
11+
>T : Symbol(T, Decl(decls.d.ts, 1, 20))
12+
>U : Symbol(U, Decl(decls.d.ts, 1, 22))
13+
>x : Symbol(x, Decl(decls.d.ts, 1, 35))
14+
>T : Symbol(T, Decl(decls.d.ts, 1, 20))
15+
>T : Symbol(T, Decl(decls.d.ts, 1, 20))
16+
>U : Symbol(U, Decl(decls.d.ts, 1, 22))
17+
18+
declare class C0<T> {
19+
>C0 : Symbol(C0, Decl(decls.d.ts, 1, 50))
20+
>T : Symbol(T, Decl(decls.d.ts, 2, 17))
21+
22+
y: T;
23+
>y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
24+
>T : Symbol(T, Decl(decls.d.ts, 2, 17))
25+
26+
constructor(x?: T);
27+
>x : Symbol(x, Decl(decls.d.ts, 4, 16))
28+
>T : Symbol(T, Decl(decls.d.ts, 2, 17))
29+
}
30+
declare class C1<T, U = number> {
31+
>C1 : Symbol(C1, Decl(decls.d.ts, 5, 1))
32+
>T : Symbol(T, Decl(decls.d.ts, 6, 17))
33+
>U : Symbol(U, Decl(decls.d.ts, 6, 19))
34+
35+
y: [T, U];
36+
>y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
37+
>T : Symbol(T, Decl(decls.d.ts, 6, 17))
38+
>U : Symbol(U, Decl(decls.d.ts, 6, 19))
39+
40+
constructor(x?: T);
41+
>x : Symbol(x, Decl(decls.d.ts, 8, 16))
42+
>T : Symbol(T, Decl(decls.d.ts, 6, 17))
43+
}
44+
=== tests/cases/compiler/main.js ===
45+
const f0_v0 = f0();
46+
>f0_v0 : Symbol(f0_v0, Decl(main.js, 0, 5))
47+
>f0 : Symbol(f0, Decl(decls.d.ts, 0, 0))
48+
49+
const f0_v1 = f0(1);
50+
>f0_v1 : Symbol(f0_v1, Decl(main.js, 1, 5))
51+
>f0 : Symbol(f0, Decl(decls.d.ts, 0, 0))
52+
53+
const f1_c0 = f1();
54+
>f1_c0 : Symbol(f1_c0, Decl(main.js, 3, 5))
55+
>f1 : Symbol(f1, Decl(decls.d.ts, 0, 33))
56+
57+
const f1_c1 = f1(1);
58+
>f1_c1 : Symbol(f1_c1, Decl(main.js, 4, 5))
59+
>f1 : Symbol(f1, Decl(decls.d.ts, 0, 33))
60+
61+
const C0_v0 = new C0();
62+
>C0_v0 : Symbol(C0_v0, Decl(main.js, 6, 5))
63+
>C0 : Symbol(C0, Decl(decls.d.ts, 1, 50))
64+
65+
const C0_v0_y = C0_v0.y;
66+
>C0_v0_y : Symbol(C0_v0_y, Decl(main.js, 7, 5))
67+
>C0_v0.y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
68+
>C0_v0 : Symbol(C0_v0, Decl(main.js, 6, 5))
69+
>y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
70+
71+
const C0_v1 = new C0(1);
72+
>C0_v1 : Symbol(C0_v1, Decl(main.js, 9, 5))
73+
>C0 : Symbol(C0, Decl(decls.d.ts, 1, 50))
74+
75+
const C0_v1_y = C0_v1.y;
76+
>C0_v1_y : Symbol(C0_v1_y, Decl(main.js, 10, 5))
77+
>C0_v1.y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
78+
>C0_v1 : Symbol(C0_v1, Decl(main.js, 9, 5))
79+
>y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
80+
81+
const C1_v0 = new C1();
82+
>C1_v0 : Symbol(C1_v0, Decl(main.js, 12, 5))
83+
>C1 : Symbol(C1, Decl(decls.d.ts, 5, 1))
84+
85+
const C1_v0_y = C1_v0.y;
86+
>C1_v0_y : Symbol(C1_v0_y, Decl(main.js, 13, 5))
87+
>C1_v0.y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
88+
>C1_v0 : Symbol(C1_v0, Decl(main.js, 12, 5))
89+
>y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
90+
91+
const C1_v1 = new C1(1);
92+
>C1_v1 : Symbol(C1_v1, Decl(main.js, 15, 5))
93+
>C1 : Symbol(C1, Decl(decls.d.ts, 5, 1))
94+
95+
const C1_v1_y = C1_v1.y;
96+
>C1_v1_y : Symbol(C1_v1_y, Decl(main.js, 16, 5))
97+
>C1_v1.y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
98+
>C1_v1 : Symbol(C1_v1, Decl(main.js, 15, 5))
99+
>y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
100+
101+
class C0_B0 extends C0 {}
102+
>C0_B0 : Symbol(C0_B0, Decl(main.js, 16, 24))
103+
>C0 : Symbol(C0, Decl(decls.d.ts, 1, 50))
104+
105+
class C0_B1 extends C0 {
106+
>C0_B1 : Symbol(C0_B1, Decl(main.js, 18, 25))
107+
>C0 : Symbol(C0, Decl(decls.d.ts, 1, 50))
108+
109+
constructor() {
110+
super();
111+
>super : Symbol(C0, Decl(decls.d.ts, 1, 50))
112+
}
113+
}
114+
class C0_B2 extends C0 {
115+
>C0_B2 : Symbol(C0_B2, Decl(main.js, 23, 1))
116+
>C0 : Symbol(C0, Decl(decls.d.ts, 1, 50))
117+
118+
constructor() {
119+
super(1);
120+
>super : Symbol(C0, Decl(decls.d.ts, 1, 50))
121+
}
122+
}
123+
124+
const C0_B0_v0 = new C0_B0();
125+
>C0_B0_v0 : Symbol(C0_B0_v0, Decl(main.js, 30, 5))
126+
>C0_B0 : Symbol(C0_B0, Decl(main.js, 16, 24))
127+
128+
const C0_B0_v0_y = C0_B0_v0.y;
129+
>C0_B0_v0_y : Symbol(C0_B0_v0_y, Decl(main.js, 31, 5))
130+
>C0_B0_v0.y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
131+
>C0_B0_v0 : Symbol(C0_B0_v0, Decl(main.js, 30, 5))
132+
>y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
133+
134+
const C0_B0_v1 = new C0_B0(1);
135+
>C0_B0_v1 : Symbol(C0_B0_v1, Decl(main.js, 33, 5))
136+
>C0_B0 : Symbol(C0_B0, Decl(main.js, 16, 24))
137+
138+
const C0_B0_v1_y = C0_B0_v1.y;
139+
>C0_B0_v1_y : Symbol(C0_B0_v1_y, Decl(main.js, 34, 5))
140+
>C0_B0_v1.y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
141+
>C0_B0_v1 : Symbol(C0_B0_v1, Decl(main.js, 33, 5))
142+
>y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
143+
144+
const C0_B1_v0 = new C0_B1();
145+
>C0_B1_v0 : Symbol(C0_B1_v0, Decl(main.js, 36, 5))
146+
>C0_B1 : Symbol(C0_B1, Decl(main.js, 18, 25))
147+
148+
const C0_B1_v0_y = C0_B1_v0.y;
149+
>C0_B1_v0_y : Symbol(C0_B1_v0_y, Decl(main.js, 37, 5))
150+
>C0_B1_v0.y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
151+
>C0_B1_v0 : Symbol(C0_B1_v0, Decl(main.js, 36, 5))
152+
>y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
153+
154+
const C0_B2_v0 = new C0_B2();
155+
>C0_B2_v0 : Symbol(C0_B2_v0, Decl(main.js, 39, 5))
156+
>C0_B2 : Symbol(C0_B2, Decl(main.js, 23, 1))
157+
158+
const C0_B2_v0_y = C0_B2_v0.y;
159+
>C0_B2_v0_y : Symbol(C0_B2_v0_y, Decl(main.js, 40, 5))
160+
>C0_B2_v0.y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
161+
>C0_B2_v0 : Symbol(C0_B2_v0, Decl(main.js, 39, 5))
162+
>y : Symbol(C0.y, Decl(decls.d.ts, 2, 21))
163+
164+
class C1_B0 extends C1 {}
165+
>C1_B0 : Symbol(C1_B0, Decl(main.js, 40, 30))
166+
>C1 : Symbol(C1, Decl(decls.d.ts, 5, 1))
167+
168+
class C1_B1 extends C1 {
169+
>C1_B1 : Symbol(C1_B1, Decl(main.js, 42, 25))
170+
>C1 : Symbol(C1, Decl(decls.d.ts, 5, 1))
171+
172+
constructor() {
173+
super();
174+
>super : Symbol(C1, Decl(decls.d.ts, 5, 1))
175+
}
176+
}
177+
class C1_B2 extends C1 {
178+
>C1_B2 : Symbol(C1_B2, Decl(main.js, 47, 1))
179+
>C1 : Symbol(C1, Decl(decls.d.ts, 5, 1))
180+
181+
constructor() {
182+
super(1);
183+
>super : Symbol(C1, Decl(decls.d.ts, 5, 1))
184+
}
185+
}
186+
187+
const C1_B0_v0 = new C1_B0();
188+
>C1_B0_v0 : Symbol(C1_B0_v0, Decl(main.js, 54, 5))
189+
>C1_B0 : Symbol(C1_B0, Decl(main.js, 40, 30))
190+
191+
const C1_B0_v0_y = C1_B0_v0.y;
192+
>C1_B0_v0_y : Symbol(C1_B0_v0_y, Decl(main.js, 55, 5))
193+
>C1_B0_v0.y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
194+
>C1_B0_v0 : Symbol(C1_B0_v0, Decl(main.js, 54, 5))
195+
>y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
196+
197+
const C1_B0_v1 = new C1_B0(1);
198+
>C1_B0_v1 : Symbol(C1_B0_v1, Decl(main.js, 57, 5))
199+
>C1_B0 : Symbol(C1_B0, Decl(main.js, 40, 30))
200+
201+
const C1_B0_v1_y = C1_B0_v1.y;
202+
>C1_B0_v1_y : Symbol(C1_B0_v1_y, Decl(main.js, 58, 5))
203+
>C1_B0_v1.y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
204+
>C1_B0_v1 : Symbol(C1_B0_v1, Decl(main.js, 57, 5))
205+
>y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
206+
207+
const C1_B1_v0 = new C1_B1();
208+
>C1_B1_v0 : Symbol(C1_B1_v0, Decl(main.js, 60, 5))
209+
>C1_B1 : Symbol(C1_B1, Decl(main.js, 42, 25))
210+
211+
const C1_B1_v0_y = C1_B1_v0.y;
212+
>C1_B1_v0_y : Symbol(C1_B1_v0_y, Decl(main.js, 61, 5))
213+
>C1_B1_v0.y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
214+
>C1_B1_v0 : Symbol(C1_B1_v0, Decl(main.js, 60, 5))
215+
>y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
216+
217+
const C1_B2_v0 = new C1_B2();
218+
>C1_B2_v0 : Symbol(C1_B2_v0, Decl(main.js, 63, 5))
219+
>C1_B2 : Symbol(C1_B2, Decl(main.js, 47, 1))
220+
221+
const C1_B2_v0_y = C1_B2_v0.y;
222+
>C1_B2_v0_y : Symbol(C1_B2_v0_y, Decl(main.js, 64, 5))
223+
>C1_B2_v0.y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
224+
>C1_B2_v0 : Symbol(C1_B2_v0, Decl(main.js, 63, 5))
225+
>y : Symbol(C1.y, Decl(decls.d.ts, 6, 33))
226+

0 commit comments

Comments
 (0)