How do I add attributes to existing HTML elements in TypeScript/JSX?

一笑奈何 提交于 2019-11-29 03:27:52

Looks like in older versions of type definition files (v0.14) the interfaces were simply declared under a global React namespace, so previously you could use the standard merging syntax.

declare namespace React {

    interface HTMLProps<T> extends HTMLAttributes, ClassAttributes<T> {
    }
}

However the new version of d.ts file (v15.0) have declared everything inside a module. Since modules do not support merging, to the best of my knowledge the only option right now seems to be module augmentation: https://www.typescriptlang.org/docs/handbook/declaration-merging.html

I did the following experiment and it worked for me:

import * as React from 'react';

declare module 'react' {
     interface HTMLProps<T> {
        block?:string;
        element?:string;
        modifiers?:string;
    }

}

export const Foo = () => {

    return (
        <div block="123" element="456">
        </div>
    )
};

Obviously this is quite tedious, you could put the augmentation code in another file as shown in the example from the typescript handbook, and import it:

import * as React from 'react';
import './react_augmented';

But it's still quite dirty. So maybe it's best to address the issue with the contributors of the type definition file.

I wanted to use glamor's createElement replacement which adds a css prop to every element.

To add to the accepted answer, module augmentation seems to do the trick but HTMLProps only worked for non-input elements. The correct interfaces to extend seems to be HTMLAttributes and SVGAttributes.

declare module 'react' {
  interface HTMLAttributes<T> {
    css?: any
  }

  interface SVGAttributes<T> {
    css?: any
  }
}

To avoid importing the module augmentation in every component, re-export createElement:

// createElement.ts
import { createElement } from 'glamor/react'

declare module 'react' {
  interface HTMLAttributes<T> {
    css?: any
  }

  interface SVGAttributes<T> {
    css?: any
  }
}

export default createElement

Then tell TS to use our createElement for JSX with this tsconfig:

{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "createElement"
  }
}

Usage:

// MyComponent.tsx
import createElement from './createElement'

export default function MyComponent() {
  return <div css={{ color: 'red' }} />
}

An up-to-date example (May 2019)

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;
  }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!