【问题标题】:How do I add attributes to existing HTML elements in TypeScript/JSX?如何向 TypeScript/JSX 中的现有 HTML 元素添加属性?
【发布时间】:2017-02-26 20:47:28
【问题描述】:

有人知道如何使用自定义属性正确添加/扩展所有原生 HTML 元素属性吗?

有了the TypeScript documentation for merging interfaces,我认为我可以这样做:

interface HTMLElement {
    block?: BEM.Block;
    element?: BEM.Element;
    modifiers?: BEM.Modifiers;
}

<div block="foo" />; // error

但我在 vscode 1.6.1(最新)中收到以下 Intellisense 错误:

[ts] 类型“HTMLProps”上不存在属性“block”。

他们所指的HTMLPropsReact.HTMLProps&lt;T&gt;div 元素被声明为这样使用它:

namespace JSX {
    interface IntrinsicElements {
        div: React.HTMLProps<HTMLDivElement>
    }
}

我尝试重新声明div,但无济于事。

相关:https://github.com/Microsoft/TypeScript/issues/11684

编辑:以下是最终为我工作的:

declare module 'react' {
    interface HTMLAttributes<T> extends DOMAttributes<T> {
        block?: string
        element?: string
        modifiers?: Modifiers // <-- custom interface
    }
}

【问题讨论】:

  • @MadaraUchiha extending React.HTMLProps&lt;T&gt; 怎么样?甚至将声明与React.HTMLProps&lt;T&gt;合并?
  • @ZevSpitz 我都试过了,但效果不佳。扩展没有帮助,因为我不能强迫它使用我的界面,它只会使用React.HTMLProps&lt;T&gt;,而合并声明根本不起作用,它完全忽略了它们。如果您可以提出一个可行的案例,请考虑将其发布为答案。
  • @MadaraUchiha 合并声明根本行不通我猜你的意思是namespace React { interface HTMLProps&lt;T&gt; { /*custom elements here*/ } }?不知道HTMLProps声明长啥样,可能需要匹配一下。
  • 我有一个问题:为什么需要这个?使用data-*属性有问题吗?
  • 你能创建 Playground、codepen 或 jsfiddle 吗?

标签: typescript jsx


【解决方案1】:

看起来在旧版本的类型定义文件 (v0.14) 中,接口只是在全局 React 命名空间下声明,因此以前您可以使用标准的合并语法。

declare namespace React {

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

但是,新版本的 d.ts 文件 (v15.0) 已经声明了模块内的所有内容。由于模块不支持合并,据我所知,目前唯一的选择似乎是module augmentationhttps://www.typescriptlang.org/docs/handbook/declaration-merging.html

我做了以下实验,它对我有用:

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>
    )
};

显然这很乏味,您可以将扩充代码放在另一个文件中,如 typescript 手册中的示例所示,然后导入:

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

但它仍然很脏。所以也许最好解决类型定义文件的贡献者的问题。

【讨论】:

  • 谢谢!与此同时,我们以另一种方式解决了这个问题,但这是一个详细的答案,其中包含解决问题所需的一切。你有我的 +1 和赏金。好工作! :)
  • @Madara'sGhost 你能分享一下你解决这个问题的其他方法吗?
  • @nishanths 我不能,因为我什至不记得我在什么情况下遇到了这个特殊问题。对不起。
【解决方案2】:

我想使用 glamor 的 createElement 替换,它为每个元素添加一个 css 属性。

要添加到已接受的答案,模块扩充似乎可以解决问题,但 HTMLProps 仅适用于非输入元素。正确的扩展接口似乎是HTMLAttributesSVGAttributes

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

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

为避免在每个组件中导入模块扩充,重新导出 createElement:

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

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

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

export default createElement

然后通过这个 tsconfig 告诉 TS 使用我们的 createElement 用于 JSX:

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

用法:

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

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

【讨论】:

    【解决方案3】:

    最新示例(2019 年 5 月)

    React 类型定义文件(默认情况下 - index.d.tscreate-react-app 一起使用时)包含所有标准 HTML 元素的列表,以及已知属性。

    为了允许自定义 HTML 属性,您需要定义它的类型。 通过扩展HTMLAttributes 接口来做到这一点:

    declare module 'react' {
      interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
        // extends React's HTMLAttributes
        custom?: string;
      }
    }
    

    【讨论】:

      【解决方案4】:

      带有 TSX 的 Vue 3

      // src/index.d.ts
      
      import * as vue from 'vue';
      declare module 'vue' {
        interface HTMLAttributes {
          className?: string;
          vHtml?: string;
          frameBorder?: string;
        }
      }
      
      

      【讨论】:

        【解决方案5】:

        对于 vue,以下工作:

        declare module 'vue-tsx-support/types/dom' {
            interface InputHTMLAttributes  {
                autocorrect: string;
                autocapitalize
            }
        }
        

        【讨论】:

        • 你有任何有效的例子吗?
        猜你喜欢
        • 2021-09-16
        • 2011-12-26
        • 1970-01-01
        • 1970-01-01
        • 2022-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多