diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4152aad0c84..697ccb89060 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7600,7 +7600,7 @@ namespace ts { return true; } else if (getPropertyOfType(type, name) || (isComparingJsxAttributes && !isUnhyphenatedJsxName(name))) { - // For JSXAttributes, if the attribute has hyphenated name considered the attribute to be known + // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true; } } @@ -11281,27 +11281,19 @@ namespace ts { function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute) { // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give JSXAttributes a contextual type - // which is a type of the parameter of the signature we are trying out. This is not the case if it is a statefull Jsx (i.e ReactComponenet class) + // which is a type of the parameter of the signature we are trying out. This is not the case if it is a stateful JSX (i.e ReactComponenet class) // So if that is the case, just return the type of the JsxAttribute in such contextual type with out going into resolving of the JsxOpeningLikeElement again - if ((attribute.parent).contextualType) { - return isJsxAttribute(attribute) ? getTypeOfPropertyOfType((attribute.parent).contextualType, attribute.name.text) : undefined; - } + const attributesType = getContextualType(attribute.parent) || getAttributesTypeFromJsxOpeningLikeElement(attribute.parent.parent); - const kind = attribute.kind; - const jsxElement = attribute.parent.parent as JsxOpeningLikeElement; - const attrsType = getAttributesTypeFromJsxOpeningLikeElement(jsxElement); - - if (kind === SyntaxKind.JsxAttribute) { - if (!attrsType || isTypeAny(attrsType)) { + if (isJsxAttribute(attribute)) { + if (!attributesType || isTypeAny(attributesType)) { return undefined; } - return getTypeOfPropertyOfType(attrsType, (attribute as JsxAttribute).name.text); + return getTypeOfPropertyOfType(attributesType, (attribute as JsxAttribute).name.text); } - else if (kind === SyntaxKind.JsxSpreadAttribute) { - return attrsType; + else { + return attributesType; } - - Debug.fail(`Expected JsxAttribute or JsxSpreadAttribute, got ts.SyntaxKind[${kind}]`); } // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily @@ -11992,7 +11984,7 @@ namespace ts { let sourceAttributesType = anyType as Type; let isSourceAttributesTypeEmpty = true; if (symbolArray) { - // Filter out any hyphenated names as those are not play any role in type-checking unless there are corresponding properties in the target type + // Filter out any hyphenated names as those do not play any role in type-checking unless there are corresponding properties in the target type const symbolTable = createMap(); forEach(symbolArray, (attr) => { if (isUnhyphenatedJsxName(attr.name) || getPropertyOfType(targetAttributesType, attr.name)) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e85e6f6aacd..f7aa3a41d53 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1507,14 +1507,13 @@ attributes: JsxAttributes; } - // @kind(SyntaxKind.JsxAttribute) export interface JsxAttribute extends ObjectLiteralElement { + kind: SyntaxKind.JsxAttribute; name: Identifier; /// JSX attribute initializers are optional; is sugar for initializer?: StringLiteral | JsxExpression; } - // @kind(SyntaxKind.JsxSpreadAttribute) export interface JsxSpreadAttribute extends ObjectLiteralElement { kind: SyntaxKind.JsxSpreadAttribute; expression: Expression; diff --git a/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt b/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt index 9b6371a1df8..31f06c48b62 100644 --- a/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt +++ b/tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes02.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(28,24): error TS2322: Type '{ extra: true; onClick: (k: any) => void; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. +tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(28,24): error TS2322: Type '{ extra: true; onClick: (k: "left" | "right") => void; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(29,24): error TS2322: Type '{ onClick: (k: "left" | "right") => void; extra: true; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. Property 'onClick' does not exist on type 'IntrinsicAttributes & LinkProps'. @@ -6,7 +6,7 @@ tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(30,24): err Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(31,24): error TS2322: Type '{ goTo: "home"; extra: true; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. -tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(34,25): error TS2322: Type '{ extra: true; onClick: (k: any) => void; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. +tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(34,25): error TS2322: Type '{ extra: true; onClick: (k: "left" | "right") => void; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & ButtonProps'. tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(37,25): error TS2322: Type '{ extra: true; goTo: "home"; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. @@ -42,7 +42,7 @@ tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(37,25): err const b0 = {console.log(k)}}} extra />; // k has type any ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ extra: true; onClick: (k: any) => void; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. +!!! error TS2322: Type '{ extra: true; onClick: (k: "left" | "right") => void; }' is not assignable to type 'IntrinsicAttributes & LinkProps'. !!! error TS2322: Property 'extra' does not exist on type 'IntrinsicAttributes & LinkProps'. const b2 = {console.log(k)}} extra />; // k has type "left" | "right" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -60,7 +60,7 @@ tests/cases/conformance/types/contextualTypes/jsxAttributes/file.tsx(37,25): err export function NoOverload(buttonProps: ButtonProps): JSX.Element { return undefined } const c1 = {console.log(k)}}} extra />; // k has type any ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ extra: true; onClick: (k: any) => void; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. +!!! error TS2322: Type '{ extra: true; onClick: (k: "left" | "right") => void; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'. !!! error TS2322: Property 'extra' does not exist on type 'IntrinsicAttributes & ButtonProps'. export function NoOverload1(linkProps: LinkProps): JSX.Element { return undefined } diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt index 807dfa78ebc..1190ce2c4f3 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentOverload5.errors.txt @@ -4,7 +4,7 @@ tests/cases/conformance/jsx/file.tsx(50,24): error TS2322: Type '{ to: string; o Property 'to' does not exist on type 'IntrinsicAttributes & HyphenProps'. tests/cases/conformance/jsx/file.tsx(51,24): error TS2322: Type '{ onClick: () => void; to: string; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'. Property 'onClick' does not exist on type 'IntrinsicAttributes & HyphenProps'. -tests/cases/conformance/jsx/file.tsx(52,24): error TS2322: Type '{ onClick: (k: any) => void; to: string; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'. +tests/cases/conformance/jsx/file.tsx(52,24): error TS2322: Type '{ onClick: (k: MouseEvent) => void; to: string; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'. Property 'onClick' does not exist on type 'IntrinsicAttributes & HyphenProps'. tests/cases/conformance/jsx/file.tsx(54,24): error TS2322: Type '{ to: string; onClick(e: any): void; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'. Property 'to' does not exist on type 'IntrinsicAttributes & HyphenProps'. @@ -81,7 +81,7 @@ tests/cases/conformance/jsx/file.tsx(57,24): error TS2322: Type '{ data-format: !!! error TS2322: Property 'onClick' does not exist on type 'IntrinsicAttributes & HyphenProps'. const b3 = {}}} />; // extra property ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ onClick: (k: any) => void; to: string; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'. +!!! error TS2322: Type '{ onClick: (k: MouseEvent) => void; to: string; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'. !!! error TS2322: Property 'onClick' does not exist on type 'IntrinsicAttributes & HyphenProps'. const b4 = ; // Should error because Incorrect type; but attributes are any so everything is allowed const b5 = ; // Spread retain method declaration (see GitHub #13365), so now there is an extra attributes