mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
feat(45679): support 'did you mean' diagnostics for string literal union (#45723)
* feat(45679): support 'did you mean' diagnostics for string literal union * Format suggested type with `typeToString` * Address feedback
This commit is contained in:
parent
8523ac8bc9
commit
4f8aa5239e
@ -17831,6 +17831,13 @@ namespace ts {
|
||||
message = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties;
|
||||
}
|
||||
else {
|
||||
if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.Union) {
|
||||
const suggestedType = getSuggestedTypeForNonexistentStringLiteralType(source as StringLiteralType, target as UnionType);
|
||||
if (suggestedType) {
|
||||
reportError(Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, generalizedSourceType, targetType, typeToString(suggestedType));
|
||||
return;
|
||||
}
|
||||
}
|
||||
message = Diagnostics.Type_0_is_not_assignable_to_type_1;
|
||||
}
|
||||
}
|
||||
@ -28230,6 +28237,11 @@ namespace ts {
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
function getSuggestedTypeForNonexistentStringLiteralType(source: StringLiteralType, target: UnionType): StringLiteralType | undefined {
|
||||
const candidates = target.types.filter((type): type is StringLiteralType => !!(type.flags & TypeFlags.StringLiteral));
|
||||
return getSpellingSuggestion(source.value, candidates, type => type.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a name and a list of symbols whose names are *not* equal to the name, return a spelling suggestion if there is one that is close enough.
|
||||
* Names less than length 3 only check for case-insensitive equality, not levenshtein distance.
|
||||
|
||||
@ -3300,6 +3300,10 @@
|
||||
"category": "Error",
|
||||
"code": 2819
|
||||
},
|
||||
"Type '{0}' is not assignable to type '{1}'. Did you mean '{2}'?": {
|
||||
"category": "Error",
|
||||
"code": 2820
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
20
tests/baselines/reference/didYouMeanStringLiteral.errors.txt
Normal file
20
tests/baselines/reference/didYouMeanStringLiteral.errors.txt
Normal file
@ -0,0 +1,20 @@
|
||||
tests/cases/compiler/didYouMeanStringLiteral.ts(5,7): error TS2820: Type '"strong"' is not assignable to type 'T1'. Did you mean '"string"'?
|
||||
tests/cases/compiler/didYouMeanStringLiteral.ts(6,7): error TS2322: Type '"strong"' is not assignable to type '"number" | "boolean"'.
|
||||
tests/cases/compiler/didYouMeanStringLiteral.ts(7,7): error TS2820: Type '"strong"' is not assignable to type '"string" | "boolean"'. Did you mean '"string"'?
|
||||
|
||||
|
||||
==== tests/cases/compiler/didYouMeanStringLiteral.ts (3 errors) ====
|
||||
type T1 = "string" | "number" | "boolean";
|
||||
type T2 = T1 & ("number" | "boolean"); // "number" | "boolean"
|
||||
type T3 = T1 & ("string" | "boolean"); // "string" | "boolean"
|
||||
|
||||
const t1: T1 = "strong";
|
||||
~~
|
||||
!!! error TS2820: Type '"strong"' is not assignable to type 'T1'. Did you mean '"string"'?
|
||||
const t2: T2 = "strong";
|
||||
~~
|
||||
!!! error TS2322: Type '"strong"' is not assignable to type '"number" | "boolean"'.
|
||||
const t3: T3 = "strong";
|
||||
~~
|
||||
!!! error TS2820: Type '"strong"' is not assignable to type '"string" | "boolean"'. Did you mean '"string"'?
|
||||
|
||||
14
tests/baselines/reference/didYouMeanStringLiteral.js
Normal file
14
tests/baselines/reference/didYouMeanStringLiteral.js
Normal file
@ -0,0 +1,14 @@
|
||||
//// [didYouMeanStringLiteral.ts]
|
||||
type T1 = "string" | "number" | "boolean";
|
||||
type T2 = T1 & ("number" | "boolean"); // "number" | "boolean"
|
||||
type T3 = T1 & ("string" | "boolean"); // "string" | "boolean"
|
||||
|
||||
const t1: T1 = "strong";
|
||||
const t2: T2 = "strong";
|
||||
const t3: T3 = "strong";
|
||||
|
||||
|
||||
//// [didYouMeanStringLiteral.js]
|
||||
var t1 = "strong";
|
||||
var t2 = "strong";
|
||||
var t3 = "strong";
|
||||
24
tests/baselines/reference/didYouMeanStringLiteral.symbols
Normal file
24
tests/baselines/reference/didYouMeanStringLiteral.symbols
Normal file
@ -0,0 +1,24 @@
|
||||
=== tests/cases/compiler/didYouMeanStringLiteral.ts ===
|
||||
type T1 = "string" | "number" | "boolean";
|
||||
>T1 : Symbol(T1, Decl(didYouMeanStringLiteral.ts, 0, 0))
|
||||
|
||||
type T2 = T1 & ("number" | "boolean"); // "number" | "boolean"
|
||||
>T2 : Symbol(T2, Decl(didYouMeanStringLiteral.ts, 0, 42))
|
||||
>T1 : Symbol(T1, Decl(didYouMeanStringLiteral.ts, 0, 0))
|
||||
|
||||
type T3 = T1 & ("string" | "boolean"); // "string" | "boolean"
|
||||
>T3 : Symbol(T3, Decl(didYouMeanStringLiteral.ts, 1, 38))
|
||||
>T1 : Symbol(T1, Decl(didYouMeanStringLiteral.ts, 0, 0))
|
||||
|
||||
const t1: T1 = "strong";
|
||||
>t1 : Symbol(t1, Decl(didYouMeanStringLiteral.ts, 4, 5))
|
||||
>T1 : Symbol(T1, Decl(didYouMeanStringLiteral.ts, 0, 0))
|
||||
|
||||
const t2: T2 = "strong";
|
||||
>t2 : Symbol(t2, Decl(didYouMeanStringLiteral.ts, 5, 5))
|
||||
>T2 : Symbol(T2, Decl(didYouMeanStringLiteral.ts, 0, 42))
|
||||
|
||||
const t3: T3 = "strong";
|
||||
>t3 : Symbol(t3, Decl(didYouMeanStringLiteral.ts, 6, 5))
|
||||
>T3 : Symbol(T3, Decl(didYouMeanStringLiteral.ts, 1, 38))
|
||||
|
||||
22
tests/baselines/reference/didYouMeanStringLiteral.types
Normal file
22
tests/baselines/reference/didYouMeanStringLiteral.types
Normal file
@ -0,0 +1,22 @@
|
||||
=== tests/cases/compiler/didYouMeanStringLiteral.ts ===
|
||||
type T1 = "string" | "number" | "boolean";
|
||||
>T1 : T1
|
||||
|
||||
type T2 = T1 & ("number" | "boolean"); // "number" | "boolean"
|
||||
>T2 : "number" | "boolean"
|
||||
|
||||
type T3 = T1 & ("string" | "boolean"); // "string" | "boolean"
|
||||
>T3 : "string" | "boolean"
|
||||
|
||||
const t1: T1 = "strong";
|
||||
>t1 : T1
|
||||
>"strong" : "strong"
|
||||
|
||||
const t2: T2 = "strong";
|
||||
>t2 : "number" | "boolean"
|
||||
>"strong" : "strong"
|
||||
|
||||
const t3: T3 = "strong";
|
||||
>t3 : "string" | "boolean"
|
||||
>"strong" : "strong"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts(11,11): error TS2322: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'.
|
||||
tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts(16,11): error TS2322: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'.
|
||||
tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts(11,11): error TS2820: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'. Did you mean '"hddvd"'?
|
||||
tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts(16,11): error TS2820: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'. Did you mean '"hddvd"'?
|
||||
|
||||
|
||||
==== tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts (2 errors) ====
|
||||
@ -15,7 +15,7 @@ tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts(16,11): error TS232
|
||||
{ kind: "bluray", },
|
||||
{ kind: "hdpvd", }
|
||||
~~~~
|
||||
!!! error TS2322: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'.
|
||||
!!! error TS2820: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'. Did you mean '"hddvd"'?
|
||||
!!! related TS6500 tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts:3:13: The expected type comes from property 'kind' which is declared here on type 'Disc'
|
||||
]);
|
||||
|
||||
@ -23,7 +23,7 @@ tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts(16,11): error TS232
|
||||
{ kind: "bluray", },
|
||||
{ kind: "hdpvd", }
|
||||
~~~~
|
||||
!!! error TS2322: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'.
|
||||
!!! error TS2820: Type '"hdpvd"' is not assignable to type '"hddvd" | "bluray"'. Did you mean '"hddvd"'?
|
||||
!!! related TS6500 tests/cases/compiler/errorsForCallAndAssignmentAreSimilar.ts:3:13: The expected type comes from property 'kind' which is declared here on type 'Disc'
|
||||
];
|
||||
}
|
||||
7
tests/cases/compiler/didYouMeanStringLiteral.ts
Normal file
7
tests/cases/compiler/didYouMeanStringLiteral.ts
Normal file
@ -0,0 +1,7 @@
|
||||
type T1 = "string" | "number" | "boolean";
|
||||
type T2 = T1 & ("number" | "boolean"); // "number" | "boolean"
|
||||
type T3 = T1 & ("string" | "boolean"); // "string" | "boolean"
|
||||
|
||||
const t1: T1 = "strong";
|
||||
const t2: T2 = "strong";
|
||||
const t3: T3 = "strong";
|
||||
Loading…
x
Reference in New Issue
Block a user