diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bd576cecbfda6..48103dafb9102 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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; } diff --git a/tests/baselines/reference/ignoredJsxAttributes.errors.txt b/tests/baselines/reference/ignoredJsxAttributes.errors.txt new file mode 100644 index 0000000000000..db428fd588fc9 --- /dev/null +++ b/tests/baselines/reference/ignoredJsxAttributes.errors.txt @@ -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) ==== + /// + + // 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 = ; + let x2 = ; // 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. + \ No newline at end of file diff --git a/tests/baselines/reference/ignoredJsxAttributes.js b/tests/baselines/reference/ignoredJsxAttributes.js new file mode 100644 index 0000000000000..4aa89833cab09 --- /dev/null +++ b/tests/baselines/reference/ignoredJsxAttributes.js @@ -0,0 +1,35 @@ +//// [ignoredJsxAttributes.tsx] +/// + +// 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 = ; +let x2 = ; // Error + + +//// [ignoredJsxAttributes.js] +"use strict"; +/// +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 diff --git a/tests/baselines/reference/ignoredJsxAttributes.symbols b/tests/baselines/reference/ignoredJsxAttributes.symbols new file mode 100644 index 0000000000000..3e7db8969c7ad --- /dev/null +++ b/tests/baselines/reference/ignoredJsxAttributes.symbols @@ -0,0 +1,49 @@ +=== tests/cases/compiler/ignoredJsxAttributes.tsx === +/// + +// 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 = ; +>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 = ; // 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)) + diff --git a/tests/baselines/reference/ignoredJsxAttributes.types b/tests/baselines/reference/ignoredJsxAttributes.types new file mode 100644 index 0000000000000..ec8500a13e546 --- /dev/null +++ b/tests/baselines/reference/ignoredJsxAttributes.types @@ -0,0 +1,51 @@ +=== tests/cases/compiler/ignoredJsxAttributes.tsx === +/// + +// 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 = ; +>x1 : JSX.Element +> : JSX.Element +>Yadda : (props: Props) => JSX.Element +>foo : string +>data-yadda : number +>42 : 42 + +let x2 = ; // Error +>x2 : JSX.Element +> : JSX.Element +>Yadda : (props: Props) => JSX.Element +>bar : string +>data-yadda : number +>42 : 42 + diff --git a/tests/baselines/reference/tsxAttributeResolution7.errors.txt b/tests/baselines/reference/tsxAttributeResolution7.errors.txt index f36d8eaa0ad8f..307aa54df5f47 100644 --- a/tests/baselines/reference/tsxAttributeResolution7.errors.txt +++ b/tests/baselines/reference/tsxAttributeResolution7.errors.txt @@ -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 ; - ~~~~~~~~ -!!! 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 ; diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentOverload4.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentOverload4.errors.txt index 2513a3ba14c1c..57ddd4acd2253 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentOverload4.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentOverload4.errors.txt @@ -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 = - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~ !!! 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 = ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt index fc177bee73b79..84db546e73c6c 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt @@ -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 = ; // 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' \ No newline at end of file +!!! related TS2728 tests/cases/conformance/jsx/file.tsx:13:5: 'to' is declared here. \ No newline at end of file diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt index d31c2afc5607a..4f59b5a4e89c0 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt @@ -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(arg: T) { let a1 = ; - ~~~~~~~~~~~ -!!! 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 diff --git a/tests/cases/compiler/ignoredJsxAttributes.tsx b/tests/cases/compiler/ignoredJsxAttributes.tsx new file mode 100644 index 0000000000000..b4eb5337b1fb0 --- /dev/null +++ b/tests/cases/compiler/ignoredJsxAttributes.tsx @@ -0,0 +1,22 @@ +// @strict: true +// @jsx: react +/// + +// 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 = ; +let x2 = ; // Error