javascriptreactjstypescriptvue.jsjsx

Why kebab-case non-standard attributes are allowed while others aren't? And how to define types like this in TypeScript?


Using foo as an attribute throws an error:

// App.tsx
//                     👇 throws
const App = () => <div foo></div>

export default App
Type '{ foo: true; }' is not assignable to type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.
  Property 'foo' does not exist on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.ts(2322)

But using foo-foo is fine, why's that?

// App.tsx
//                     👇 no error is thrown
const App = () => <div foo-foo></div>

export default App

And most importantly, how to define types like this in TypeScript? i.e. Only allowing standard or kebab-case attributes.


Solution

  • The answer to the "why" part of your question is in the JSX section of the Typescript Handbook:

    If an attribute name is not a valid JS identifier (like a data-* attribute), it is not considered to be an error if it is not found in the element attributes type.

    The entire section on JSX is a very enlightening read.

    I'm afraid the answer to the "how to define types like this in TypeScript" question is... We don't. JSX support is built into the compiler. Derek Nguyen's answer suggest the use of template literal types, maybe is something to investigate further.