mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Again: Improve error messages for empty DOM interface property access (#43007)
* Again: Improve error messages for empty DOM interface property access * containerSeemsToBeEmptyDomElement Co-authored-by: Daniel Rosenwasser <drosenwasser@microsoft.com> * isEmptyObjectType; unescapeLeadingUnderscores * Single tick quotes for now * Undo accidental diagnostic change * Correct new baseline Co-authored-by: Daniel Rosenwasser <drosenwasser@microsoft.com> Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
This commit is contained in:
parent
905a1fea39
commit
a4c683be12
@ -22270,6 +22270,10 @@ namespace ts {
|
||||
return type.flags & TypeFlags.Union ? every((<UnionType>type).types, f) : f(type);
|
||||
}
|
||||
|
||||
function everyContainedType(type: Type, f: (t: Type) => boolean): boolean {
|
||||
return type.flags & TypeFlags.UnionOrIntersection ? every((type as UnionOrIntersectionType).types, f) : f(type);
|
||||
}
|
||||
|
||||
function filterType(type: Type, f: (t: Type) => boolean): Type {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const types = (<UnionType>type).types;
|
||||
@ -27336,7 +27340,10 @@ 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, missingProperty, container);
|
||||
const diagnostic = containerSeemsToBeEmptyDomElement(containingType)
|
||||
? Diagnostics.Property_0_does_not_exist_on_type_1_Try_changing_the_lib_compiler_option_to_include_dom
|
||||
: Diagnostics.Property_0_does_not_exist_on_type_1;
|
||||
errorInfo = chainDiagnosticMessages(elaborateNeverIntersection(errorInfo, containingType), diagnostic, missingProperty, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -27348,6 +27355,12 @@ namespace ts {
|
||||
diagnostics.add(resultDiagnostic);
|
||||
}
|
||||
|
||||
function containerSeemsToBeEmptyDomElement(containingType: Type) {
|
||||
return (compilerOptions.lib && !compilerOptions.lib.includes("dom")) &&
|
||||
everyContainedType(containingType, type => type.symbol && /^(EventTarget|Node|((HTML[a-zA-Z]*)?Element))$/.test(unescapeLeadingUnderscores(type.symbol.escapedName))) &&
|
||||
isEmptyObjectType(containingType);
|
||||
}
|
||||
|
||||
function typeHasStaticProperty(propName: __String, containingType: Type): boolean {
|
||||
const prop = containingType.symbol && getPropertyOfType(getTypeOfSymbol(containingType.symbol), propName);
|
||||
return prop !== undefined && !!prop.valueDeclaration && hasSyntacticModifier(prop.valueDeclaration, ModifierFlags.Static);
|
||||
|
||||
@ -3324,6 +3324,10 @@
|
||||
"category": "Error",
|
||||
"code": 2811
|
||||
},
|
||||
"Property '{0}' does not exist on type '{1}'. Try changing the 'lib' compiler option to include 'dom'.": {
|
||||
"category": "Error",
|
||||
"code": 2812
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
39
tests/baselines/reference/missingDomElements.errors.txt
Normal file
39
tests/baselines/reference/missingDomElements.errors.txt
Normal file
@ -0,0 +1,39 @@
|
||||
tests/cases/compiler/missingDomElements.ts(6,24): error TS2812: Property 'textContent' does not exist on type 'Element'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
tests/cases/compiler/missingDomElements.ts(7,28): error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
tests/cases/compiler/missingDomElements.ts(8,33): error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
tests/cases/compiler/missingDomElements.ts(9,47): error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
tests/cases/compiler/missingDomElements.ts(16,32): error TS2339: Property 'textContent' does not exist on type 'HTMLElementFake'.
|
||||
tests/cases/compiler/missingDomElements.ts(17,21): error TS2339: Property 'textContent' does not exist on type 'Node'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/missingDomElements.ts (6 errors) ====
|
||||
interface Element {}
|
||||
interface EventTarget {}
|
||||
interface HTMLElement {}
|
||||
interface HTMLInputElement {}
|
||||
|
||||
({} as any as Element).textContent;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2812: Property 'textContent' does not exist on type 'Element'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
({} as any as HTMLElement).textContent;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
({} as any as HTMLInputElement).textContent;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
({} as any as EventTarget & HTMLInputElement).textContent
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'.
|
||||
|
||||
interface HTMLElementFake {}
|
||||
interface Node {
|
||||
actuallyNotTheSame: number;
|
||||
};
|
||||
|
||||
({} as any as HTMLElementFake).textContent;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'textContent' does not exist on type 'HTMLElementFake'.
|
||||
({} as any as Node).textContent;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'textContent' does not exist on type 'Node'.
|
||||
|
||||
28
tests/baselines/reference/missingDomElements.js
Normal file
28
tests/baselines/reference/missingDomElements.js
Normal file
@ -0,0 +1,28 @@
|
||||
//// [missingDomElements.ts]
|
||||
interface Element {}
|
||||
interface EventTarget {}
|
||||
interface HTMLElement {}
|
||||
interface HTMLInputElement {}
|
||||
|
||||
({} as any as Element).textContent;
|
||||
({} as any as HTMLElement).textContent;
|
||||
({} as any as HTMLInputElement).textContent;
|
||||
({} as any as EventTarget & HTMLInputElement).textContent
|
||||
|
||||
interface HTMLElementFake {}
|
||||
interface Node {
|
||||
actuallyNotTheSame: number;
|
||||
};
|
||||
|
||||
({} as any as HTMLElementFake).textContent;
|
||||
({} as any as Node).textContent;
|
||||
|
||||
|
||||
//// [missingDomElements.js]
|
||||
({}.textContent);
|
||||
({}.textContent);
|
||||
({}.textContent);
|
||||
({}.textContent);
|
||||
;
|
||||
({}.textContent);
|
||||
({}.textContent);
|
||||
43
tests/baselines/reference/missingDomElements.symbols
Normal file
43
tests/baselines/reference/missingDomElements.symbols
Normal file
@ -0,0 +1,43 @@
|
||||
=== tests/cases/compiler/missingDomElements.ts ===
|
||||
interface Element {}
|
||||
>Element : Symbol(Element, Decl(missingDomElements.ts, 0, 0))
|
||||
|
||||
interface EventTarget {}
|
||||
>EventTarget : Symbol(EventTarget, Decl(missingDomElements.ts, 0, 20))
|
||||
|
||||
interface HTMLElement {}
|
||||
>HTMLElement : Symbol(HTMLElement, Decl(missingDomElements.ts, 1, 24))
|
||||
|
||||
interface HTMLInputElement {}
|
||||
>HTMLInputElement : Symbol(HTMLInputElement, Decl(missingDomElements.ts, 2, 24))
|
||||
|
||||
({} as any as Element).textContent;
|
||||
>Element : Symbol(Element, Decl(missingDomElements.ts, 0, 0))
|
||||
|
||||
({} as any as HTMLElement).textContent;
|
||||
>HTMLElement : Symbol(HTMLElement, Decl(missingDomElements.ts, 1, 24))
|
||||
|
||||
({} as any as HTMLInputElement).textContent;
|
||||
>HTMLInputElement : Symbol(HTMLInputElement, Decl(missingDomElements.ts, 2, 24))
|
||||
|
||||
({} as any as EventTarget & HTMLInputElement).textContent
|
||||
>EventTarget : Symbol(EventTarget, Decl(missingDomElements.ts, 0, 20))
|
||||
>HTMLInputElement : Symbol(HTMLInputElement, Decl(missingDomElements.ts, 2, 24))
|
||||
|
||||
interface HTMLElementFake {}
|
||||
>HTMLElementFake : Symbol(HTMLElementFake, Decl(missingDomElements.ts, 8, 57))
|
||||
|
||||
interface Node {
|
||||
>Node : Symbol(Node, Decl(missingDomElements.ts, 10, 28))
|
||||
|
||||
actuallyNotTheSame: number;
|
||||
>actuallyNotTheSame : Symbol(Node.actuallyNotTheSame, Decl(missingDomElements.ts, 11, 16))
|
||||
|
||||
};
|
||||
|
||||
({} as any as HTMLElementFake).textContent;
|
||||
>HTMLElementFake : Symbol(HTMLElementFake, Decl(missingDomElements.ts, 8, 57))
|
||||
|
||||
({} as any as Node).textContent;
|
||||
>Node : Symbol(Node, Decl(missingDomElements.ts, 10, 28))
|
||||
|
||||
61
tests/baselines/reference/missingDomElements.types
Normal file
61
tests/baselines/reference/missingDomElements.types
Normal file
@ -0,0 +1,61 @@
|
||||
=== tests/cases/compiler/missingDomElements.ts ===
|
||||
interface Element {}
|
||||
interface EventTarget {}
|
||||
interface HTMLElement {}
|
||||
interface HTMLInputElement {}
|
||||
|
||||
({} as any as Element).textContent;
|
||||
>({} as any as Element).textContent : any
|
||||
>({} as any as Element) : Element
|
||||
>{} as any as Element : Element
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
>textContent : any
|
||||
|
||||
({} as any as HTMLElement).textContent;
|
||||
>({} as any as HTMLElement).textContent : any
|
||||
>({} as any as HTMLElement) : HTMLElement
|
||||
>{} as any as HTMLElement : HTMLElement
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
>textContent : any
|
||||
|
||||
({} as any as HTMLInputElement).textContent;
|
||||
>({} as any as HTMLInputElement).textContent : any
|
||||
>({} as any as HTMLInputElement) : HTMLInputElement
|
||||
>{} as any as HTMLInputElement : HTMLInputElement
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
>textContent : any
|
||||
|
||||
({} as any as EventTarget & HTMLInputElement).textContent
|
||||
>({} as any as EventTarget & HTMLInputElement).textContent : any
|
||||
>({} as any as EventTarget & HTMLInputElement) : EventTarget & HTMLInputElement
|
||||
>{} as any as EventTarget & HTMLInputElement : EventTarget & HTMLInputElement
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
>textContent : any
|
||||
|
||||
interface HTMLElementFake {}
|
||||
interface Node {
|
||||
actuallyNotTheSame: number;
|
||||
>actuallyNotTheSame : number
|
||||
|
||||
};
|
||||
|
||||
({} as any as HTMLElementFake).textContent;
|
||||
>({} as any as HTMLElementFake).textContent : any
|
||||
>({} as any as HTMLElementFake) : HTMLElementFake
|
||||
>{} as any as HTMLElementFake : HTMLElementFake
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
>textContent : any
|
||||
|
||||
({} as any as Node).textContent;
|
||||
>({} as any as Node).textContent : any
|
||||
>({} as any as Node) : Node
|
||||
>{} as any as Node : Node
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
>textContent : any
|
||||
|
||||
19
tests/cases/compiler/missingDomElements.ts
Normal file
19
tests/cases/compiler/missingDomElements.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// @lib: esnext
|
||||
|
||||
interface Element {}
|
||||
interface EventTarget {}
|
||||
interface HTMLElement {}
|
||||
interface HTMLInputElement {}
|
||||
|
||||
({} as any as Element).textContent;
|
||||
({} as any as HTMLElement).textContent;
|
||||
({} as any as HTMLInputElement).textContent;
|
||||
({} as any as EventTarget & HTMLInputElement).textContent
|
||||
|
||||
interface HTMLElementFake {}
|
||||
interface Node {
|
||||
actuallyNotTheSame: number;
|
||||
};
|
||||
|
||||
({} as any as HTMLElementFake).textContent;
|
||||
({} as any as Node).textContent;
|
||||
Loading…
x
Reference in New Issue
Block a user