mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
fix(40320): Better errors when using properties/methods from newer versions of ECMAScript (#40650)
* Update package-lock.json * Suggesting a library for a missing property/method * Added more types and added tests * Added more tests to cover all the latest features * Added bigintarrays and dataview methods * Fixed typo in template * Transform old error message to use 2nd template slot * Removed test that has been split up between es2015 and es2016+ * Use empty arrays and remove unnecessary function call * merge * Added early bail-out and updated baselines * Implemented early bail-out (misread) Co-authored-by: TypeScript Bot <typescriptbot@microsoft.com>
This commit is contained in:
@@ -2023,7 +2023,15 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
if (!suggestion) {
|
||||
error(errorLocation, nameNotFoundMessage, diagnosticName(nameArg!));
|
||||
if (nameArg) {
|
||||
const lib = getSuggestedLibForNonExistentName(nameArg);
|
||||
if (lib) {
|
||||
error(errorLocation, nameNotFoundMessage, diagnosticName(nameArg), lib);
|
||||
}
|
||||
else {
|
||||
error(errorLocation, nameNotFoundMessage, diagnosticName(nameArg));
|
||||
}
|
||||
}
|
||||
}
|
||||
suggestionCount++;
|
||||
}
|
||||
@@ -20631,7 +20639,17 @@ namespace ts {
|
||||
case "WeakSet":
|
||||
case "Iterator":
|
||||
case "AsyncIterator":
|
||||
return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later;
|
||||
case "SharedArrayBuffer":
|
||||
case "Atomics":
|
||||
case "AsyncIterable":
|
||||
case "AsyncIterableIterator":
|
||||
case "AsyncGenerator":
|
||||
case "AsyncGeneratorFunction":
|
||||
case "BigInt":
|
||||
case "Reflect":
|
||||
case "BigInt64Array":
|
||||
case "BigUint64Array":
|
||||
return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_1_or_later;
|
||||
default:
|
||||
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
return Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer;
|
||||
@@ -25887,7 +25905,15 @@ namespace ts {
|
||||
relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName);
|
||||
}
|
||||
else {
|
||||
errorInfo = chainDiagnosticMessages(elaborateNeverIntersection(errorInfo, containingType), Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
|
||||
const missingProperty = declarationNameToString(propNode);
|
||||
const container = typeToString(containingType);
|
||||
const lib = getSuggestedLibForNonExistentProperty(missingProperty, containingType);
|
||||
if (lib) {
|
||||
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2_or_later, missingProperty, container, lib);
|
||||
}
|
||||
else {
|
||||
errorInfo = chainDiagnosticMessages(elaborateNeverIntersection(errorInfo, containingType), Diagnostics.Property_0_does_not_exist_on_type_1, missingProperty, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25903,6 +25929,34 @@ namespace ts {
|
||||
return prop !== undefined && prop.valueDeclaration && hasSyntacticModifier(prop.valueDeclaration, ModifierFlags.Static);
|
||||
}
|
||||
|
||||
function getSuggestedLibForNonExistentName(name: __String | Identifier) {
|
||||
const missingName = diagnosticName(name);
|
||||
const allFeatures = getScriptTargetFeatures();
|
||||
const libTargets = getOwnKeys(allFeatures);
|
||||
for (const libTarget of libTargets) {
|
||||
const containingTypes = getOwnKeys(allFeatures[libTarget]);
|
||||
if (containingTypes !== undefined && contains(containingTypes, missingName)) {
|
||||
return libTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSuggestedLibForNonExistentProperty(missingProperty: string, containingType: Type) {
|
||||
const container = getApparentType(containingType).symbol;
|
||||
if (!container) {
|
||||
return undefined;
|
||||
}
|
||||
const allFeatures = getScriptTargetFeatures();
|
||||
const libTargets = getOwnKeys(allFeatures);
|
||||
for (const libTarget of libTargets) {
|
||||
const featuresOfLib = allFeatures[libTarget];
|
||||
const featuresOfContainingType = featuresOfLib[symbolName(container)];
|
||||
if (featuresOfContainingType !== undefined && contains(featuresOfContainingType, missingProperty)) {
|
||||
return libTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined {
|
||||
return getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value);
|
||||
}
|
||||
@@ -25992,6 +26046,7 @@ namespace ts {
|
||||
*/
|
||||
function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined {
|
||||
return getSpellingSuggestion(name, symbols, getCandidateName);
|
||||
|
||||
function getCandidateName(candidate: Symbol) {
|
||||
const candidateName = symbolName(candidate);
|
||||
if (startsWith(candidateName, "\"")) {
|
||||
|
||||
@@ -2197,6 +2197,10 @@
|
||||
"category": "Error",
|
||||
"code": 2549
|
||||
},
|
||||
"Property '{0}' does not exist on type '{1}'. Do you need to change your target library? Try changing the `lib` compiler option to '{2}' or later.": {
|
||||
"category": "Error",
|
||||
"code": 2550
|
||||
},
|
||||
"Property '{0}' does not exist on type '{1}'. Did you mean '{2}'?": {
|
||||
"category": "Error",
|
||||
"code": 2551
|
||||
@@ -2313,7 +2317,7 @@
|
||||
"category": "Error",
|
||||
"code": 2582
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.": {
|
||||
"Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to '{1}' or later.": {
|
||||
"category": "Error",
|
||||
"code": 2583
|
||||
},
|
||||
|
||||
@@ -540,6 +540,76 @@ namespace ts {
|
||||
return emitNode && emitNode.flags || 0;
|
||||
}
|
||||
|
||||
interface ScriptTargetFeatures {
|
||||
[key: string]: { [key: string]: string[] | undefined };
|
||||
};
|
||||
|
||||
export function getScriptTargetFeatures(): ScriptTargetFeatures {
|
||||
return {
|
||||
es2015: {
|
||||
Array: ["find", "findIndex", "fill", "copyWithin", "entries", "keys", "values"],
|
||||
RegExp: ["flags", "sticky", "unicode"],
|
||||
Reflect: ["apply", "construct", "defineProperty", "deleteProperty", "get"," getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"],
|
||||
ArrayConstructor: ["from", "of"],
|
||||
ObjectConstructor: ["assign", "getOwnPropertySymbols", "keys", "is", "setPrototypeOf"],
|
||||
NumberConstructor: ["isFinite", "isInteger", "isNaN", "isSafeInteger", "parseFloat", "parseInt"],
|
||||
Math: ["clz32", "imul", "sign", "log10", "log2", "log1p", "expm1", "cosh", "sinh", "tanh", "acosh", "asinh", "atanh", "hypot", "trunc", "fround", "cbrt"],
|
||||
Map: ["entries", "keys", "values"],
|
||||
Set: ["entries", "keys", "values"],
|
||||
Promise: ["all", "race", "reject", "resolve"],
|
||||
Symbol: ["for", "keyFor"],
|
||||
WeakMap: ["entries", "keys", "values"],
|
||||
WeakSet: ["entries", "keys", "values"],
|
||||
Iterator: emptyArray,
|
||||
AsyncIterator: emptyArray,
|
||||
String: ["codePointAt", "includes", "endsWith", "normalize", "repeat", "startsWith", "anchor", "big", "blink", "bold", "fixed", "fontcolor", "fontsize", "italics", "link", "small", "strike", "sub", "sup"],
|
||||
StringConstructor: ["fromCodePoint", "raw"]
|
||||
},
|
||||
es2016: {
|
||||
Array: ["includes"]
|
||||
},
|
||||
es2017: {
|
||||
Atomics: emptyArray,
|
||||
SharedArrayBuffer: emptyArray,
|
||||
String: ["padStart", "padEnd"],
|
||||
ObjectConstructor: ["values", "entries", "getOwnPropertyDescriptors"],
|
||||
DateTimeFormat: ["formatToParts"]
|
||||
},
|
||||
es2018: {
|
||||
Promise: ["finally"],
|
||||
RegExpMatchArray: ["groups"],
|
||||
RegExpExecArray: ["groups"],
|
||||
RegExp: ["dotAll"],
|
||||
Intl: ["PluralRules"],
|
||||
AsyncIterable: emptyArray,
|
||||
AsyncIterableIterator: emptyArray,
|
||||
AsyncGenerator: emptyArray,
|
||||
AsyncGeneratorFunction: emptyArray,
|
||||
},
|
||||
es2019: {
|
||||
Array: ["flat", "flatMap"],
|
||||
ObjectConstructor: ["fromEntries"],
|
||||
String: ["trimStart", "trimEnd", "trimLeft", "trimRight"],
|
||||
Symbol: ["description"]
|
||||
},
|
||||
es2020: {
|
||||
BigInt: emptyArray,
|
||||
BigInt64Array: emptyArray,
|
||||
BigUint64Array: emptyArray,
|
||||
Promise: ["allSettled"],
|
||||
SymbolConstructor: ["matchAll"],
|
||||
String: ["matchAll"],
|
||||
DataView: ["setBigInt64", "setBigUint64", "getBigInt64", "getBigUint64"],
|
||||
RelativeTimeFormat: ["format", "formatToParts", "resolvedOptions"]
|
||||
},
|
||||
esnext: {
|
||||
Promise: ["any"],
|
||||
String: ["replaceAll"],
|
||||
NumberFormat: ["formatToParts"]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const enum GetLiteralTextFlags {
|
||||
None = 0,
|
||||
NeverAsciiEscape = 1 << 0,
|
||||
@@ -5733,7 +5803,6 @@ namespace ts {
|
||||
if (arguments.length > 2) {
|
||||
text = formatStringFromArgs(text, arguments, 2);
|
||||
}
|
||||
|
||||
return {
|
||||
messageText: text,
|
||||
category: message.category,
|
||||
|
||||
Reference in New Issue
Block a user