Repository: TypeScript
Issue: Enforce property rules on kebab-cased JSX attributes
Labels: Suggestion,Awaiting More Feedback

# Bug Report


Reference: https://github.com/microsoft/TypeScript/issues/32447

I thought it was a good idea to reopen this given it's been 4 years and TS's features have advanced substantially since that last issue was filed and closed.

Quoting @RyanCavanaugh

> This is the intended behavior because of data- and aria- properties. If we ever get regex-based property names, we'll revisit.

Given we now have template literal types - this is probably ripe for revisiting!

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

<!--
  What search terms did you use when trying to find an existing bug report?
  List them here so people in the future can find this one more easily.
-->
jsx dash property missing error kebab case

### 🕗 Version & Regression Information

<!-- When did you start seeing this bug occur?

"Bugs" that have existed in TS for a long time are very likely to be FAQs; refer to
  https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

If possible, please try testing the nightly version of TS to see if it's already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly

Note: The TypeScript Playground can be used to try older versions of TypeScript.

Please keep and fill in the line that best applies:
-->
- This is the behavior in every version I tried

### ⏯ Playground Link

<!--
  A link to a TypeScript Playground "Share" link which shows this behavior.
  This should have the same code as the code snippet below, and use whichever settings are relevant to your report.

  As a last resort, you can link to a repo, but these will be slower for us to investigate.
-->
[Playground link with relevant code](https://www.typescriptlang.org/play?#code/C4TwDgpgBACgTgezAZygXigbwFBSgQwH4AuKZYOASwDsBzAGlygHJkEBbCAWgGsIAjfPy5hEkOKGYko-BAgA2EfNQDc2AL5QAZFiYBtHlBpQABgBN8wfFwAkmclTrqTUAD6n8Va3Yc1azt1MACwh5eQQfCj9nAF1pXzoNbV08AyNqFj5BYQBjfGQIAEZmQOYsoS48goAmZjjSBNoNNQAzAFdqHOBKBAyAYQ4wXohqYAAKUSRkUngpgEosKDgIYDa4DOo2sKh1bGx2zu7eqAB5YBC4MYWcPAAeAfYh6hHgJjx8NExCzQB6H6hAKDkUAgAA9IF0IGZgXBEHAmG8ZJ9vlA-oDgWCIBCoRAYQg4Xg8AiQmEEEjfv8gaDwcBIUTQuEACoXCBklEU9HU2kEqAIzyUazyIShNAAIhFbLRADd8PJKGYERYrFwWnJReLUUDpbL5XgfgA+NRMVGAZXJobDUMdztAcoNhqN6EtLBcoOdlC6QlBJuJQEx7rbnqMEeVcvkimSgwIKlUINVw7qDXtdf9TTjzVBLR6bY87cAHXAnTj3W6rZ6xDifXcHk8Xgi2JxeJHhF7yyA4yiE76qzmFZZrII4KzUYAZcjIQQQW2xuLgMjawCgZgQEGQ1GYr3jhsr-pr3ObEhAXFdwC4ZggLRolBp8n3C6Xoy4oMo5C4IBWB+Qx8X7+oCCPqbxXF6LgL0+FoZQKckoBHZAxwnM08RnOcb2XVcjQTXZsBPHJBWWKAbWocgoAAJSULpSE2MI1CAA)

### 💻 Code

<!-- Please post the relevant code sample here as well. This code and the Playground code should be the same, do not use separate examples -->
```tsx
type Props = {
  a?: string,
  'some-kebab-property'?: boolean;
} & {
  [k in `data-${string}` | `aria-${string}` | `hello${string}`]?: string
} & {
  [k in 'kebab-case1' | 'kebab-case2']?: string
};
function Component(props: Props) { return null }

function Other() {
  <Component
    a={1} // ✅ expected error
  
    b={1} // ✅ expected error
    
    hello={1} // ✅ expected
    helloThere={1} // ✅ expected
    
    aria-label="" // ✅ valid
    data-foo="" // ✅ valid
  />;

  // ❓ errors on the component, rather than the property
  <Component
    kebab-case1={1}
    kebab-case2={1}
  />;

  // ❓ errors on the component, rather than the property
  <Component
    some-kebab-property={1}
  />;

  <Component
    data-bar={1} // ❌ should error but doesn't
  />;

  <Component
    property-that-definitely-doesnt-exist-yet-ts-does-not-error-on-it={false} // ❌ should error but doesn't
  />;
}
```

### 🙁 Actual behavior

<!-- What happened, and why it was wrong -->

This errors on the component, not the property

```tsx
  <Component
    kebab-case1={1}
    kebab-case2={1}
  />;

  <Component
    some-kebab-property={1}
  />;
```

These do not error at all

```tsx
  <Component
    data-bar={1}
  />;

  <Component
    property-that-definitely-doesnt-exist-yet-ts-does-not-error-on-it={false}
  />;
```

### 🙂 Expected behavior

<!-- What you expected to happen instead, and why -->

This should error on the property - but it errors on the component instead

```tsx
  <Component
    kebab-case1={1}
    kebab-case2={1}
  />;

  <Component
    some-kebab-property={1}
  />;
```

Should error because it doesn't match the defined template literal mapped type

```tsx
  <Component
    data-bar={1}
  />;
```

Should error because the property doesn't exist

```tsx
  <Component
    property-that-definitely-doesnt-exist-yet-ts-does-not-error-on-it={false}
  />;
```