Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the TypeScript engine to allow custom HTML attributes in JSX?

I presume the TypeScript engine within Visual Studio Code has received an update that is now complaining for the first time that my pre-existing custom props on HTML elements are invalid. This is on a Babel/React/JSX project with no TypeScript whatsoever.

<div custom="bar" />

Note: they are (technically) invalid, but I consume them, so I know what I'm doing (it's intentional).

See it on CodePen!

See also

  • How do I add attributes to existing HTML elements in TypeScript/JSX? (posted by myself over a year ago and doesn't work any more).
  • JSX | Type Checking
like image 685
jedmao Avatar asked Feb 15 '18 23:02

jedmao


3 Answers

React type definition file (by default - index.d.ts when staring with create-react-app) contain list of all the standard HTML elements, as well as known attributes.

In order to allow custom HTML attributes, you need to define it's typing. Do that by expanding HTMLAttributes interface:

declare module 'react' {
  interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
    // extends React's HTMLAttributes
    custom?: string;
  }
}
like image 127
yuval.bl Avatar answered Sep 19 '22 07:09

yuval.bl


Note: 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.

<div data-custom="bar" />

https://www.typescriptlang.org/docs/handbook/jsx.html#attribute-type-checking https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*

like image 45
Iceli Avatar answered Sep 22 '22 07:09

Iceli


Project structure:

☁  extends-react-types  tree -I 'node_modules' 
.
├── App.tsx
├── index.d.ts
├── package-lock.json
├── package.json
└── tsconfig.json

0 directories, 5 files

package version:

{
  "name": "extends-react-types",
  "devDependencies": {
    "@types/react": "^16.9.56",
    "typescript": "^4.3.5"
  },
  "dependencies": {
    "react": "^16.8.6"
  }
}

tsconfig.json:

{
    "compilerOptions": {
        "target": "es5",
        "lib": [
            "dom"
        ],
        "allowSyntheticDefaultImports": true,
        "moduleResolution": "Node",
        "jsx": "preserve",
    }
}

App.tsx:

import React from 'react';

interface HomeProps extends React.ComponentPropsWithRef<'div'> {}
export default function Home(props: HomeProps) {
  return (
    <div>
      <p _name="name" _error={true}>
        123
      </p>
    </div>
  );
}

As you can see, there are two custom HTML attributes in p element: _name and _error. Now, we need to extend HTMLAttributes interface of React with these two custom HTML attributes.

Option 1:

index.d.ts:

import 'react';

declare module 'react' {
  interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
    _name?: string;
    _error?: boolean;
  }
}

Output:

enter image description here

Option 2:

declare namespace React {
  interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
    _name?: string;
    _error?: boolean;
  }
}

Output:

enter image description here

like image 35
slideshowp2 Avatar answered Sep 22 '22 07:09

slideshowp2