如何向 TypeScript/JSX 中的现有 HTML 元素添加属性?
Posted
技术标签:
【中文标题】如何向 TypeScript/JSX 中的现有 HTML 元素添加属性?【英文标题】:How do I add attributes to existing HTML elements in TypeScript/JSX? 【发布时间】: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”。
他们所指的HTMLProps
是React.HTMLProps<T>
,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
【问题讨论】:
@MadaraUchihaextend
ing React.HTMLProps<T>
怎么样?甚至将声明与React.HTMLProps<T>
合并?
@ZevSpitz 我都试过了,但效果不佳。扩展没有帮助,因为我不能强迫它使用我的界面,它只会使用React.HTMLProps<T>
,而合并声明根本不起作用,它完全忽略了它们。如果您可以提出一个可行的案例,请考虑将其发布为答案。
@MadaraUchiha 合并声明根本行不通我猜你的意思是namespace React interface HTMLProps<T> /*custom elements here*/
?不知道HTMLProps
声明长啥样,可能需要匹配一下。
我有一个问题:为什么需要这个?使用data-*
属性有问题吗?
你能创建 Playground、codepen 或 jsfiddle 吗?
【参考方案1】:
看起来在旧版本的类型定义文件 (v0.14) 中,接口只是在全局 React 命名空间下声明,因此以前您可以使用标准的合并语法。
declare namespace React
interface HTMLProps<T> extends HTMLAttributes, ClassAttributes<T>
但是,新版本的 d.ts 文件 (v15.0) 已经声明了模块内的所有内容。由于模块不支持合并,据我所知,目前唯一的选择似乎是module augmentation
:
https://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
仅适用于非输入元素。正确的扩展接口似乎是HTMLAttributes
和SVGAttributes
。
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.ts
与 create-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
【讨论】:
你有任何有效的例子吗?以上是关于如何向 TypeScript/JSX 中的现有 HTML 元素添加属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何在带有 React 的 Typescript/JSX 中使用带有箭头函数的泛型?
带有泛型的 Typescript JSX - 参数隐式具有“任何”类型