mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 04:43:37 -05:00
Consistently ignore attributes with hyphenated names in JSX (#44873)
* Consistently skip attributes with hyphenated names in JSX * Add regression test * Accept new baselines * Fix tests * Accept new baselines
This commit is contained in:
@@ -16794,7 +16794,7 @@ namespace ts {
|
||||
function *generateJsxAttributes(node: JsxAttributes): ElaborationIterator {
|
||||
if (!length(node.properties)) return;
|
||||
for (const prop of node.properties) {
|
||||
if (isJsxSpreadAttribute(prop)) continue;
|
||||
if (isJsxSpreadAttribute(prop) || isHyphenatedJsxName(idText(prop.name))) continue;
|
||||
yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: getStringLiteralType(idText(prop.name)) };
|
||||
}
|
||||
}
|
||||
@@ -17355,7 +17355,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isIgnoredJsxProperty(source: Type, sourceProp: Symbol) {
|
||||
return getObjectFlags(source) & ObjectFlags.JsxAttributes && !isUnhyphenatedJsxName(sourceProp.escapedName);
|
||||
return getObjectFlags(source) & ObjectFlags.JsxAttributes && isHyphenatedJsxName(sourceProp.escapedName);
|
||||
}
|
||||
|
||||
function getNormalizedType(type: Type, writing: boolean): Type {
|
||||
@@ -26585,8 +26585,8 @@ namespace ts {
|
||||
return getJsxElementTypeAt(node) || anyType;
|
||||
}
|
||||
|
||||
function isUnhyphenatedJsxName(name: string | __String) {
|
||||
return !stringContains(name as string, "-");
|
||||
function isHyphenatedJsxName(name: string | __String) {
|
||||
return stringContains(name as string, "-");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27127,7 +27127,7 @@ namespace ts {
|
||||
if (getPropertyOfObjectType(targetType, name) ||
|
||||
getApplicableIndexInfoForName(targetType, name) ||
|
||||
isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) ||
|
||||
isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
|
||||
isComparingJsxAttributes && isHyphenatedJsxName(name)) {
|
||||
// For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known.
|
||||
return true;
|
||||
}
|
||||
|
||||
32
tests/baselines/reference/ignoredJsxAttributes.errors.txt
Normal file
32
tests/baselines/reference/ignoredJsxAttributes.errors.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
tests/cases/compiler/ignoredJsxAttributes.tsx(16,5): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/compiler/ignoredJsxAttributes.tsx(20,11): error TS2741: Property 'foo' is missing in type '{ bar: string; "data-yadda": number; }' but required in type 'Props'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/ignoredJsxAttributes.tsx (2 errors) ====
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
// Repro from #44797
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
interface Props {
|
||||
foo: string;
|
||||
[dataProp: string]: string;
|
||||
}
|
||||
|
||||
declare function Yadda(props: Props): JSX.Element;
|
||||
|
||||
let props: Props = {
|
||||
foo: "",
|
||||
"data-yadda": 42, // Error
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
!!! related TS6501 tests/cases/compiler/ignoredJsxAttributes.tsx:9:5: The expected type comes from this index signature.
|
||||
};
|
||||
|
||||
let x1 = <Yadda foo="hello" data-yadda={42}/>;
|
||||
let x2 = <Yadda bar="hello" data-yadda={42}/>; // Error
|
||||
~~~~~
|
||||
!!! error TS2741: Property 'foo' is missing in type '{ bar: string; "data-yadda": number; }' but required in type 'Props'.
|
||||
!!! related TS2728 tests/cases/compiler/ignoredJsxAttributes.tsx:8:5: 'foo' is declared here.
|
||||
|
||||
35
tests/baselines/reference/ignoredJsxAttributes.js
Normal file
35
tests/baselines/reference/ignoredJsxAttributes.js
Normal file
@@ -0,0 +1,35 @@
|
||||
//// [ignoredJsxAttributes.tsx]
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
// Repro from #44797
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
interface Props {
|
||||
foo: string;
|
||||
[dataProp: string]: string;
|
||||
}
|
||||
|
||||
declare function Yadda(props: Props): JSX.Element;
|
||||
|
||||
let props: Props = {
|
||||
foo: "",
|
||||
"data-yadda": 42, // Error
|
||||
};
|
||||
|
||||
let x1 = <Yadda foo="hello" data-yadda={42}/>;
|
||||
let x2 = <Yadda bar="hello" data-yadda={42}/>; // Error
|
||||
|
||||
|
||||
//// [ignoredJsxAttributes.js]
|
||||
"use strict";
|
||||
/// <reference path="react16.d.ts" />
|
||||
exports.__esModule = true;
|
||||
// Repro from #44797
|
||||
var React = require("react");
|
||||
var props = {
|
||||
foo: "",
|
||||
"data-yadda": 42
|
||||
};
|
||||
var x1 = React.createElement(Yadda, { foo: "hello", "data-yadda": 42 });
|
||||
var x2 = React.createElement(Yadda, { bar: "hello", "data-yadda": 42 }); // Error
|
||||
49
tests/baselines/reference/ignoredJsxAttributes.symbols
Normal file
49
tests/baselines/reference/ignoredJsxAttributes.symbols
Normal file
@@ -0,0 +1,49 @@
|
||||
=== tests/cases/compiler/ignoredJsxAttributes.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
// Repro from #44797
|
||||
|
||||
import * as React from "react";
|
||||
>React : Symbol(React, Decl(ignoredJsxAttributes.tsx, 4, 6))
|
||||
|
||||
interface Props {
|
||||
>Props : Symbol(Props, Decl(ignoredJsxAttributes.tsx, 4, 31))
|
||||
|
||||
foo: string;
|
||||
>foo : Symbol(Props.foo, Decl(ignoredJsxAttributes.tsx, 6, 17))
|
||||
|
||||
[dataProp: string]: string;
|
||||
>dataProp : Symbol(dataProp, Decl(ignoredJsxAttributes.tsx, 8, 5))
|
||||
}
|
||||
|
||||
declare function Yadda(props: Props): JSX.Element;
|
||||
>Yadda : Symbol(Yadda, Decl(ignoredJsxAttributes.tsx, 9, 1))
|
||||
>props : Symbol(props, Decl(ignoredJsxAttributes.tsx, 11, 23))
|
||||
>Props : Symbol(Props, Decl(ignoredJsxAttributes.tsx, 4, 31))
|
||||
>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12))
|
||||
>Element : Symbol(JSX.Element, Decl(react16.d.ts, 2494, 23))
|
||||
|
||||
let props: Props = {
|
||||
>props : Symbol(props, Decl(ignoredJsxAttributes.tsx, 13, 3))
|
||||
>Props : Symbol(Props, Decl(ignoredJsxAttributes.tsx, 4, 31))
|
||||
|
||||
foo: "",
|
||||
>foo : Symbol(foo, Decl(ignoredJsxAttributes.tsx, 13, 20))
|
||||
|
||||
"data-yadda": 42, // Error
|
||||
>"data-yadda" : Symbol("data-yadda", Decl(ignoredJsxAttributes.tsx, 14, 12))
|
||||
|
||||
};
|
||||
|
||||
let x1 = <Yadda foo="hello" data-yadda={42}/>;
|
||||
>x1 : Symbol(x1, Decl(ignoredJsxAttributes.tsx, 18, 3))
|
||||
>Yadda : Symbol(Yadda, Decl(ignoredJsxAttributes.tsx, 9, 1))
|
||||
>foo : Symbol(foo, Decl(ignoredJsxAttributes.tsx, 18, 15))
|
||||
>data-yadda : Symbol(data-yadda, Decl(ignoredJsxAttributes.tsx, 18, 27))
|
||||
|
||||
let x2 = <Yadda bar="hello" data-yadda={42}/>; // Error
|
||||
>x2 : Symbol(x2, Decl(ignoredJsxAttributes.tsx, 19, 3))
|
||||
>Yadda : Symbol(Yadda, Decl(ignoredJsxAttributes.tsx, 9, 1))
|
||||
>bar : Symbol(bar, Decl(ignoredJsxAttributes.tsx, 19, 15))
|
||||
>data-yadda : Symbol(data-yadda, Decl(ignoredJsxAttributes.tsx, 19, 27))
|
||||
|
||||
51
tests/baselines/reference/ignoredJsxAttributes.types
Normal file
51
tests/baselines/reference/ignoredJsxAttributes.types
Normal file
@@ -0,0 +1,51 @@
|
||||
=== tests/cases/compiler/ignoredJsxAttributes.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
// Repro from #44797
|
||||
|
||||
import * as React from "react";
|
||||
>React : typeof React
|
||||
|
||||
interface Props {
|
||||
foo: string;
|
||||
>foo : string
|
||||
|
||||
[dataProp: string]: string;
|
||||
>dataProp : string
|
||||
}
|
||||
|
||||
declare function Yadda(props: Props): JSX.Element;
|
||||
>Yadda : (props: Props) => JSX.Element
|
||||
>props : Props
|
||||
>JSX : any
|
||||
|
||||
let props: Props = {
|
||||
>props : Props
|
||||
>{ foo: "", "data-yadda": 42, // Error} : { foo: string; "data-yadda": number; }
|
||||
|
||||
foo: "",
|
||||
>foo : string
|
||||
>"" : ""
|
||||
|
||||
"data-yadda": 42, // Error
|
||||
>"data-yadda" : number
|
||||
>42 : 42
|
||||
|
||||
};
|
||||
|
||||
let x1 = <Yadda foo="hello" data-yadda={42}/>;
|
||||
>x1 : JSX.Element
|
||||
><Yadda foo="hello" data-yadda={42}/> : JSX.Element
|
||||
>Yadda : (props: Props) => JSX.Element
|
||||
>foo : string
|
||||
>data-yadda : number
|
||||
>42 : 42
|
||||
|
||||
let x2 = <Yadda bar="hello" data-yadda={42}/>; // Error
|
||||
>x2 : JSX.Element
|
||||
><Yadda bar="hello" data-yadda={42}/> : JSX.Element
|
||||
>Yadda : (props: Props) => JSX.Element
|
||||
>bar : string
|
||||
>data-yadda : number
|
||||
>42 : 42
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
tests/cases/conformance/jsx/file.tsx(9,8): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(9,2): error TS2322: Type '{ "data-foo": number; }' is not assignable to type '{ "data-foo"?: string; }'.
|
||||
Types of property '"data-foo"' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
|
||||
@@ -11,9 +13,10 @@ tests/cases/conformance/jsx/file.tsx(9,8): error TS2322: Type 'number' is not as
|
||||
|
||||
// Error
|
||||
<test1 data-foo={32} />;
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:4:12: The expected type comes from property 'data-foo' which is declared here on type '{ "data-foo"?: string; }'
|
||||
~~~~~
|
||||
!!! error TS2322: Type '{ "data-foo": number; }' is not assignable to type '{ "data-foo"?: string; }'.
|
||||
!!! error TS2322: Types of property '"data-foo"' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
|
||||
// OK
|
||||
<test1 data-foo={'32'} />;
|
||||
|
||||
@@ -31,9 +31,11 @@ tests/cases/conformance/jsx/file.tsx(17,13): error TS2769: No overload matches t
|
||||
Type '{ yy: boolean; yy1: string; }' is not assignable to type '{ yy: number; yy1: string; }'.
|
||||
Types of property 'yy' are incompatible.
|
||||
Type 'boolean' is not assignable to type 'number'.
|
||||
tests/cases/conformance/jsx/file.tsx(25,12): error TS2769: No overload matches this call.
|
||||
tests/cases/conformance/jsx/file.tsx(25,13): error TS2769: No overload matches this call.
|
||||
Overload 1 of 2, '(j: { "extra-data": string; }): Element', gave the following error.
|
||||
Type 'boolean' is not assignable to type 'string'.
|
||||
Type '{ "extra-data": true; }' is not assignable to type '{ "extra-data": string; }'.
|
||||
Types of property '"extra-data"' are incompatible.
|
||||
Type 'boolean' is not assignable to type 'string'.
|
||||
Overload 2 of 2, '(n: { yy: string; direction?: number; }): Element', gave the following error.
|
||||
Property 'yy' is missing in type '{ "extra-data": true; }' but required in type '{ yy: string; direction?: number; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(26,12): error TS2769: No overload matches this call.
|
||||
@@ -142,13 +144,14 @@ tests/cases/conformance/jsx/file.tsx(36,12): error TS2769: No overload matches t
|
||||
|
||||
// Error
|
||||
const d1 = <TestingOneThing extra-data />
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS2769: No overload matches this call.
|
||||
!!! error TS2769: Overload 1 of 2, '(j: { "extra-data": string; }): Element', gave the following error.
|
||||
!!! error TS2769: Type 'boolean' is not assignable to type 'string'.
|
||||
!!! error TS2769: Type '{ "extra-data": true; }' is not assignable to type '{ "extra-data": string; }'.
|
||||
!!! error TS2769: Types of property '"extra-data"' are incompatible.
|
||||
!!! error TS2769: Type 'boolean' is not assignable to type 'string'.
|
||||
!!! error TS2769: Overload 2 of 2, '(n: { yy: string; direction?: number; }): Element', gave the following error.
|
||||
!!! error TS2769: Property 'yy' is missing in type '{ "extra-data": true; }' but required in type '{ yy: string; direction?: number; }'.
|
||||
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:21:38: The expected type comes from property 'extra-data' which is declared here on type 'IntrinsicAttributes & { "extra-data": string; }'
|
||||
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:22:38: 'yy' is declared here.
|
||||
const d2 = <TestingOneThing yy="hello" direction="left" />
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -22,13 +22,15 @@ tests/cases/conformance/jsx/file.tsx(55,68): error TS2769: No overload matches t
|
||||
Type 'boolean' is not assignable to type 'string'.
|
||||
Overload 3 of 3, '(hyphenProps: HyphenProps): Element', gave the following error.
|
||||
Type 'boolean' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(56,12): error TS2769: No overload matches this call.
|
||||
tests/cases/conformance/jsx/file.tsx(56,13): error TS2769: No overload matches this call.
|
||||
Overload 1 of 3, '(buttonProps: ButtonProps): Element', gave the following error.
|
||||
Property 'onClick' is missing in type '{ "data-format": true; }' but required in type 'ButtonProps'.
|
||||
Overload 2 of 3, '(linkProps: LinkProps): Element', gave the following error.
|
||||
Property 'to' is missing in type '{ "data-format": true; }' but required in type 'LinkProps'.
|
||||
Overload 3 of 3, '(hyphenProps: HyphenProps): Element', gave the following error.
|
||||
Type 'boolean' is not assignable to type 'string'.
|
||||
Type '{ "data-format": true; }' is not assignable to type 'HyphenProps'.
|
||||
Types of property '"data-format"' are incompatible.
|
||||
Type 'boolean' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (4 errors) ====
|
||||
@@ -122,14 +124,15 @@ tests/cases/conformance/jsx/file.tsx(56,12): error TS2769: No overload matches t
|
||||
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:5:5: The expected type comes from property 'className' which is declared here on type 'IntrinsicAttributes & LinkProps'
|
||||
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:5:5: The expected type comes from property 'className' which is declared here on type 'IntrinsicAttributes & HyphenProps'
|
||||
const b8 = <MainButton data-format />; // incorrect type for specified hyphanated name
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~
|
||||
!!! error TS2769: No overload matches this call.
|
||||
!!! error TS2769: Overload 1 of 3, '(buttonProps: ButtonProps): Element', gave the following error.
|
||||
!!! error TS2769: Property 'onClick' is missing in type '{ "data-format": true; }' but required in type 'ButtonProps'.
|
||||
!!! error TS2769: Overload 2 of 3, '(linkProps: LinkProps): Element', gave the following error.
|
||||
!!! error TS2769: Property 'to' is missing in type '{ "data-format": true; }' but required in type 'LinkProps'.
|
||||
!!! error TS2769: Overload 3 of 3, '(hyphenProps: HyphenProps): Element', gave the following error.
|
||||
!!! error TS2769: Type 'boolean' is not assignable to type 'string'.
|
||||
!!! error TS2769: Type '{ "data-format": true; }' is not assignable to type 'HyphenProps'.
|
||||
!!! error TS2769: Types of property '"data-format"' are incompatible.
|
||||
!!! error TS2769: Type 'boolean' is not assignable to type 'string'.
|
||||
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:9:5: 'onClick' is declared here.
|
||||
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:13:5: 'to' is declared here.
|
||||
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:17:5: The expected type comes from property 'data-format' which is declared here on type 'IntrinsicAttributes & HyphenProps'
|
||||
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:13:5: 'to' is declared here.
|
||||
@@ -1,4 +1,7 @@
|
||||
tests/cases/conformance/jsx/file.tsx(8,43): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(8,15): error TS2322: Type 'T & { "ignore-prop": number; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'.
|
||||
Type 'T & { "ignore-prop": number; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'.
|
||||
Types of property '"ignore-prop"' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(13,15): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { prop: unknown; "ignore-prop": string; }'.
|
||||
Type 'T' is not assignable to type '{ prop: unknown; "ignore-prop": string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(20,19): error TS2322: Type '(a: number, b: string) => void' is not assignable to type '(arg: number) => void'.
|
||||
@@ -16,9 +19,11 @@ tests/cases/conformance/jsx/file.tsx(31,52): error TS2322: Type '(val: string) =
|
||||
// Error
|
||||
function Bar<T extends {prop: number}>(arg: T) {
|
||||
let a1 = <ComponentSpecific1 {...arg} ignore-prop={10} />;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:3:53: The expected type comes from property 'ignore-prop' which is declared here on type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'T & { "ignore-prop": number; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Type 'T & { "ignore-prop": number; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Types of property '"ignore-prop"' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
}
|
||||
|
||||
// Error
|
||||
|
||||
22
tests/cases/compiler/ignoredJsxAttributes.tsx
Normal file
22
tests/cases/compiler/ignoredJsxAttributes.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
// @strict: true
|
||||
// @jsx: react
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
// Repro from #44797
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
interface Props {
|
||||
foo: string;
|
||||
[dataProp: string]: string;
|
||||
}
|
||||
|
||||
declare function Yadda(props: Props): JSX.Element;
|
||||
|
||||
let props: Props = {
|
||||
foo: "",
|
||||
"data-yadda": 42, // Error
|
||||
};
|
||||
|
||||
let x1 = <Yadda foo="hello" data-yadda={42}/>;
|
||||
let x2 = <Yadda bar="hello" data-yadda={42}/>; // Error
|
||||
Reference in New Issue
Block a user