Skip to content

Commit 00ef5ae

Browse files
committed
Expand constraint suggestion related span and add quick fix
1 parent e6808c4 commit 00ef5ae

File tree

81 files changed

+318
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+318
-13
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18792,8 +18792,9 @@ namespace ts {
1879218792
return;
1879318793
}
1879418794
reportRelationError(headMessage, source, target);
18795-
if (strictNullChecks && source.flags & TypeFlags.TypeVariable && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable) && isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
18796-
associateRelatedInfo(createDiagnosticForNode(source.symbol.declarations[0], Diagnostics.This_type_parameter_probably_needs_an_extends_object_constraint));
18795+
if (source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable)) {
18796+
const targetConstraintString = typeToString(target, source.symbol.declarations[0]);
18797+
associateRelatedInfo(createDiagnosticForNode(source.symbol.declarations[0], Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, targetConstraintString));
1879718798
}
1879818799
}
1879918800

src/compiler/diagnosticMessages.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1530,7 +1530,7 @@
15301530
"category": "Error",
15311531
"code": 2207
15321532
},
1533-
"This type parameter probably needs an `extends object` constraint.": {
1533+
"This type parameter might need an `extends {0}` constraint.": {
15341534
"category": "Error",
15351535
"code": 2208
15361536
},
@@ -1543,6 +1543,10 @@
15431543
"category": "Error",
15441544
"code": 2210
15451545
},
1546+
"Add `extends` constraint.": {
1547+
"category": "Message",
1548+
"code": 2211
1549+
},
15461550

15471551
"Duplicate identifier '{0}'.": {
15481552
"category": "Error",
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
const fixId = "addMissingConstraint";
4+
const errorCodes = [
5+
// We want errors this could be attached to:
6+
// Diagnostics.This_type_parameter_probably_needs_an_extends_0_constraint
7+
Diagnostics.Type_0_is_not_comparable_to_type_1.code,
8+
Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated.code,
9+
Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code,
10+
Diagnostics.Type_0_is_not_assignable_to_type_1.code,
11+
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code,
12+
Diagnostics.Property_0_is_incompatible_with_index_signature.code,
13+
Diagnostics.Property_0_in_type_1_is_not_assignable_to_type_2.code,
14+
];
15+
registerCodeFix({
16+
errorCodes,
17+
getCodeActions(context) {
18+
const { sourceFile, span, program } = context;
19+
const related = getDiagnosticRelatedInfo(program, sourceFile, span);
20+
if (!related) {
21+
return;
22+
}
23+
const changes = textChanges.ChangeTracker.with(context, t => addMissingConstraint(t, related));
24+
return [createCodeFixAction(fixId, changes, Diagnostics.Add_extends_constraint, fixId, Diagnostics.Add_missing_new_operator_to_all_calls)];
25+
},
26+
fixIds: [fixId],
27+
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
28+
const info = getDiagnosticRelatedInfo(context.program, context.sourceFile, diag);
29+
if (!info) return;
30+
return addMissingConstraint(changes, info);
31+
}),
32+
});
33+
34+
function getDiagnosticRelatedInfo(program: Program, sourceFile: SourceFile, span: TextSpan) {
35+
const diags = program.getSemanticDiagnostics(sourceFile).filter(diag => diag.start === span.start && diag.length === span.length);
36+
if (!length(diags)) return;
37+
const diag = diags[0];
38+
if (!diag.relatedInformation) return;
39+
const related = filter(diag.relatedInformation, related => related.code === Diagnostics.This_type_parameter_might_need_an_extends_0_constraint.code)[0];
40+
if (!related) return;
41+
return related;
42+
}
43+
44+
function addMissingConstraint(changes: textChanges.ChangeTracker, related: DiagnosticRelatedInformation): void {
45+
let decl = findAncestorMatchingSpan(related.file!, related as TextSpan);
46+
if (!decl) return;
47+
if (isIdentifier(decl) && isTypeParameterDeclaration(decl.parent)) {
48+
decl = decl.parent;
49+
}
50+
if (!isTypeParameterDeclaration(decl) || isMappedTypeNode(decl.parent)) return; // should only issue fix on type parameters written using `extends`
51+
const newConstraint = flattenDiagnosticMessageText(related.messageText, "\n", 0).match(/`extends (.*)`/);
52+
if (!newConstraint) return;
53+
const newConstraintText = newConstraint[1];
54+
55+
changes.insertText(related.file!, related.start! + related.length!, ` extends ${newConstraintText}`);
56+
}
57+
58+
function findAncestorMatchingSpan(sourceFile: SourceFile, span: TextSpan): Node {
59+
let token = getTokenAtPosition(sourceFile, span.start);
60+
const end = textSpanEnd(span);
61+
while (token.end < end) {
62+
token = token.parent;
63+
}
64+
return token;
65+
}
66+
}

src/services/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"codefixes/convertLiteralTypeToMappedType.ts",
6969
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
7070
"codefixes/importFixes.ts",
71+
"codefixes/fixAddMissingConstraint.ts",
7172
"codefixes/fixOverrideModifier.ts",
7273
"codefixes/fixNoPropertyAccessFromIndexSignature.ts",
7374
"codefixes/fixImplicitThis.ts",

tests/baselines/reference/assignmentCompatWithCallSignatures3.errors.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,27 +114,31 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
114114
!!! error TS2322: Type '(x: number) => number[]' is not assignable to type '<T>(x: T) => T[]'.
115115
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
116116
!!! error TS2322: Type 'T' is not assignable to type 'number'.
117+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts:45:9: This type parameter might need an `extends number` constraint.
117118
var b2: <T>(x: T) => string[];
118119
a2 = b2; // ok
119120
b2 = a2; // ok
120121
~~
121122
!!! error TS2322: Type '(x: number) => string[]' is not assignable to type '<T>(x: T) => string[]'.
122123
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
123124
!!! error TS2322: Type 'T' is not assignable to type 'number'.
125+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts:48:10: This type parameter might need an `extends number` constraint.
124126
var b3: <T>(x: T) => T;
125127
a3 = b3; // ok
126128
b3 = a3; // ok
127129
~~
128130
!!! error TS2322: Type '(x: number) => void' is not assignable to type '<T>(x: T) => T'.
129131
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
130132
!!! error TS2322: Type 'T' is not assignable to type 'number'.
133+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts:51:10: This type parameter might need an `extends number` constraint.
131134
var b4: <T, U>(x: T, y: U) => T;
132135
a4 = b4; // ok
133136
b4 = a4; // ok
134137
~~
135138
!!! error TS2322: Type '(x: string, y: number) => string' is not assignable to type '<T, U>(x: T, y: U) => T'.
136139
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
137140
!!! error TS2322: Type 'T' is not assignable to type 'string'.
141+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts:54:10: This type parameter might need an `extends string` constraint.
138142
var b5: <T, U>(x: (arg: T) => U) => T;
139143
a5 = b5; // ok
140144
b5 = a5; // ok
@@ -227,6 +231,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
227231
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
228232
!!! error TS2322: Types of property 'a' are incompatible.
229233
!!! error TS2322: Type 'T' is not assignable to type 'string'.
234+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts:84:11: This type parameter might need an `extends string` constraint.
230235
var b15: <T>(x: T) => T[];
231236
a15 = b15; // ok
232237
b15 = a15; // ok

tests/baselines/reference/assignmentCompatWithCallSignatures4.errors.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
113113
!!! error TS2322: Type '(x: number) => string[]' is not assignable to type '<T, U>(x: T) => U[]'.
114114
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
115115
!!! error TS2322: Type 'T' is not assignable to type 'number'.
116+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts:43:18: This type parameter might need an `extends number` constraint.
116117

117118
var b7: <T extends Base, U extends Derived, V extends Derived2>(x: (arg: T) => U) => (r: T) => V;
118119
a7 = b7;
@@ -181,6 +182,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
181182
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
182183
!!! error TS2322: Types of property 'a' are incompatible.
183184
!!! error TS2322: Type 'T' is not assignable to type 'string'.
185+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts:68:19: This type parameter might need an `extends string` constraint.
184186

185187
var b15a: <T extends Base>(x: { a: T; b: T }) => number;
186188
a15 = b15a;
@@ -223,6 +225,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
223225
!!! error TS2322: Type '<T>(x: T) => T[]' is not assignable to type '<T>(x: T) => string[]'.
224226
!!! error TS2322: Type 'T[]' is not assignable to type 'string[]'.
225227
!!! error TS2322: Type 'T' is not assignable to type 'string'.
228+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts:88:18: This type parameter might need an `extends string` constraint.
226229

227230
// target type has generic call signature
228231
var a3: <T>(x: T) => string[];
@@ -232,6 +235,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
232235
!!! error TS2322: Type '<T>(x: T) => T[]' is not assignable to type '<T>(x: T) => string[]'.
233236
!!! error TS2322: Type 'T[]' is not assignable to type 'string[]'.
234237
!!! error TS2322: Type 'T' is not assignable to type 'string'.
238+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts:93:18: This type parameter might need an `extends string` constraint.
235239
b3 = a3;
236240
~~
237241
!!! error TS2322: Type '<T>(x: T) => string[]' is not assignable to type '<T>(x: T) => T[]'.

tests/baselines/reference/assignmentCompatWithCallSignatures5.errors.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
8484
!!! error TS2322: Types of property 'foo' are incompatible.
8585
!!! error TS2322: Type 'U' is not assignable to type 'T'.
8686
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.
87+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts:50:14: This type parameter might need an `extends T` constraint.
8788
var b15: <U, V>(x: { a: U; b: V; }) => U[];
8889
a15 = b15; // ok, T = U, T = V
8990
b15 = a15; // ok
@@ -94,6 +95,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
9495
!!! error TS2322: Types of property 'b' are incompatible.
9596
!!! error TS2322: Type 'V' is not assignable to type 'U'.
9697
!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'V'.
98+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts:53:14: This type parameter might need an `extends U` constraint.
9799
var b16: <T>(x: { a: T; b: T }) => T[];
98100
a15 = b16; // ok
99101
b15 = a16; // ok
@@ -103,6 +105,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
103105
!!! error TS2322: Type '{ a: U; b: V; }' is not assignable to type '{ a: Base; b: Base; }'.
104106
!!! error TS2322: Types of property 'a' are incompatible.
105107
!!! error TS2322: Type 'U' is not assignable to type 'Base'.
108+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts:53:11: This type parameter might need an `extends Base` constraint.
106109
var b17: <T>(x: (a: T) => T) => T[];
107110
a17 = b17; // ok
108111
b17 = a17; // ok

tests/baselines/reference/assignmentCompatWithCallSignatures6.errors.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
6565
!!! error TS2322: Types of property 'foo' are incompatible.
6666
!!! error TS2322: Type 'U' is not assignable to type 'T'.
6767
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.
68+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts:37:14: This type parameter might need an `extends T` constraint.
6869
var b16: <T>(x: { a: T; b: T }) => T[];
6970
x.a16 = b16;
7071
b16 = x.a16;
@@ -73,4 +74,5 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
7374
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
7475
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: Base; b: Base; }'.
7576
!!! error TS2322: Types of property 'a' are incompatible.
76-
!!! error TS2322: Type 'T' is not assignable to type 'Base'.
77+
!!! error TS2322: Type 'T' is not assignable to type 'Base'.
78+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts:40:11: This type parameter might need an `extends Base` constraint.

tests/baselines/reference/assignmentCompatWithConstructSignatures3.errors.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,27 +114,31 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
114114
!!! error TS2322: Type 'new (x: number) => number[]' is not assignable to type 'new <T>(x: T) => T[]'.
115115
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
116116
!!! error TS2322: Type 'T' is not assignable to type 'number'.
117+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts:45:13: This type parameter might need an `extends number` constraint.
117118
var b2: new <T>(x: T) => string[];
118119
a2 = b2; // ok
119120
b2 = a2; // ok
120121
~~
121122
!!! error TS2322: Type 'new (x: number) => string[]' is not assignable to type 'new <T>(x: T) => string[]'.
122123
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
123124
!!! error TS2322: Type 'T' is not assignable to type 'number'.
125+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts:48:14: This type parameter might need an `extends number` constraint.
124126
var b3: new <T>(x: T) => T;
125127
a3 = b3; // ok
126128
b3 = a3; // ok
127129
~~
128130
!!! error TS2322: Type 'new (x: number) => void' is not assignable to type 'new <T>(x: T) => T'.
129131
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
130132
!!! error TS2322: Type 'T' is not assignable to type 'number'.
133+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts:51:14: This type parameter might need an `extends number` constraint.
131134
var b4: new <T, U>(x: T, y: U) => T;
132135
a4 = b4; // ok
133136
b4 = a4; // ok
134137
~~
135138
!!! error TS2322: Type 'new (x: string, y: number) => string' is not assignable to type 'new <T, U>(x: T, y: U) => T'.
136139
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
137140
!!! error TS2322: Type 'T' is not assignable to type 'string'.
141+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts:54:14: This type parameter might need an `extends string` constraint.
138142
var b5: new <T, U>(x: (arg: T) => U) => T;
139143
a5 = b5; // ok
140144
b5 = a5; // ok
@@ -227,6 +231,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
227231
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
228232
!!! error TS2322: Types of property 'a' are incompatible.
229233
!!! error TS2322: Type 'T' is not assignable to type 'string'.
234+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures3.ts:84:15: This type parameter might need an `extends string` constraint.
230235
var b15: new <T>(x: T) => T[];
231236
a15 = b15; // ok
232237
b15 = a15; // ok

tests/baselines/reference/assignmentCompatWithConstructSignatures4.errors.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
129129
!!! error TS2322: Type 'new (x: number) => string[]' is not assignable to type 'new <T, U>(x: T) => U[]'.
130130
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
131131
!!! error TS2322: Type 'T' is not assignable to type 'number'.
132+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures4.ts:43:22: This type parameter might need an `extends number` constraint.
132133

133134
var b7: new <T extends Base, U extends Derived, V extends Derived2>(x: (arg: T) => U) => (r: T) => V;
134135
a7 = b7; // ok
@@ -197,6 +198,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
197198
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
198199
!!! error TS2322: Types of property 'a' are incompatible.
199200
!!! error TS2322: Type 'T' is not assignable to type 'string'.
201+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures4.ts:68:23: This type parameter might need an `extends string` constraint.
200202

201203
var b15a: new <T extends Base>(x: { a: T; b: T }) => number;
202204
a15 = b15a; // ok
@@ -259,6 +261,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
259261
!!! error TS2322: Type 'new <T>(x: T) => T[]' is not assignable to type 'new <T>(x: T) => string[]'.
260262
!!! error TS2322: Type 'T[]' is not assignable to type 'string[]'.
261263
!!! error TS2322: Type 'T' is not assignable to type 'string'.
264+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures4.ts:88:22: This type parameter might need an `extends string` constraint.
262265

263266
// target type has generic call signature
264267
var a3: new <T>(x: T) => string[];
@@ -268,6 +271,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
268271
!!! error TS2322: Type 'new <T>(x: T) => T[]' is not assignable to type 'new <T>(x: T) => string[]'.
269272
!!! error TS2322: Type 'T[]' is not assignable to type 'string[]'.
270273
!!! error TS2322: Type 'T' is not assignable to type 'string'.
274+
!!! related TS2208 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures4.ts:93:22: This type parameter might need an `extends string` constraint.
271275
b3 = a3; // ok
272276
~~
273277
!!! error TS2322: Type 'new <T>(x: T) => string[]' is not assignable to type 'new <T>(x: T) => T[]'.

0 commit comments

Comments
 (0)