如何向 TypeScript/JSX 中的现有 HTML 元素添加属性?
How do I add attributes to existing HTML elements in TypeScript/JSX?
有人知道如何正确 add/extend 所有原生 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] Property 'block' does not exist on type 'HTMLProps'.
他们所指的 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
}
}
看起来在旧版本的类型定义文件 (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>
)
};
显然这很繁琐,您可以将增强代码放在另一个文件中,如打字稿手册中的示例所示,然后导入它:
import * as React from 'react';
import './react_augmented';
但还是很脏。因此,也许最好与类型定义文件的贡献者一起解决这个问题。
我想使用 glamour 的 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
for JSX:
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "createElement"
}
}
用法:
// MyComponent.tsx
import createElement from './createElement'
export default function MyComponent() {
return <div css={{ color: 'red' }} />
}
一个 up-to-date 示例(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;
}
}
对于 vue,以下工作:
declare module 'vue-tsx-support/types/dom' {
interface InputHTMLAttributes {
autocorrect: string;
autocapitalize
}
}
带有 TSX 的 Vue 3
// src/index.d.ts
import * as vue from 'vue';
declare module 'vue' {
interface HTMLAttributes {
className?: string;
vHtml?: string;
frameBorder?: string;
}
}
添加来自 React TypeScript Cheatsheet
的非标准属性
// react-unstable-attributes.d.ts
import "react";
declare module "react" {
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
loading?: "auto" | "eager" | "lazy";
}
}
有人知道如何正确 add/extend 所有原生 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] Property 'block' does not exist on type 'HTMLProps'.
他们所指的 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
}
}
看起来在旧版本的类型定义文件 (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>
)
};
显然这很繁琐,您可以将增强代码放在另一个文件中,如打字稿手册中的示例所示,然后导入它:
import * as React from 'react';
import './react_augmented';
但还是很脏。因此,也许最好与类型定义文件的贡献者一起解决这个问题。
我想使用 glamour 的 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
for JSX:
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "createElement"
}
}
用法:
// MyComponent.tsx
import createElement from './createElement'
export default function MyComponent() {
return <div css={{ color: 'red' }} />
}
一个 up-to-date 示例(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;
}
}
对于 vue,以下工作:
declare module 'vue-tsx-support/types/dom' {
interface InputHTMLAttributes {
autocorrect: string;
autocapitalize
}
}
带有 TSX 的 Vue 3
// src/index.d.ts
import * as vue from 'vue';
declare module 'vue' {
interface HTMLAttributes {
className?: string;
vHtml?: string;
frameBorder?: string;
}
}
添加来自 React TypeScript Cheatsheet
的非标准属性// react-unstable-attributes.d.ts
import "react";
declare module "react" {
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
loading?: "auto" | "eager" | "lazy";
}
}