Hvordan tilføjer jeg attributter til eksisterende HTML-elementer i TypeScript/JSX?
Er der nogen, der ved, hvordan man korrekt tilføjer/udvider alle native HTML-elementattributter med brugerdefinerede?
Med TypeScript-dokumentationen for sammensmeltning af interfaces troede jeg, at jeg bare kunne gøre dette:
interface HTMLElement {
block?: BEM.Block;
element?: BEM.Element;
modifiers?: BEM.Modifiers;
}
<div block="foo" />; // error
Men jeg får følgende Intellisense-fejl i vscode 1.6.1 (seneste):
[ts] Egenskaben 'block' findes ikke på typen 'HTMLProps'.
HTMLProps, som de henviser til, er React.HTMLProps<T>, og div-elementet erklæres til at bruge det på følgende måde:
namespace JSX {
interface IntrinsicElements {
div: React.HTMLProps<HTMLDivElement>
}
}
Jeg prøvede at erklære div igen, men uden held.
Relateret: https://github.com/Microsoft/TypeScript/issues/11684
Rediger: Her er, hvad der endte med at virke for mig:
declare module 'react' {
interface HTMLAttributes<T> extends DOMAttributes<T> {
block?: string
element?: string
modifiers?: Modifiers // <-- custom interface
}
}
Svar #1
Det ser ud til, at i ældre versioner af typedefinitionsfiler (v0.14) blev interfacene simpelthen erklæret under et globalt React-namespace, så tidligere kunne man bruge den standard sammenslagningssyntaks.
declare namespace React {
interface HTMLProps<T> extends HTMLAttributes, ClassAttributes<T> {
}
}
Dog har den nye version af d.ts-filen (v15.0) erklæret alt inde i en modul. Da moduler ikke understøtter sammensmeltning, synes den eneste mulighed lige nu, så vidt jeg ved, at være module augmentation: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
Jeg udførte følgende eksperiment, og det virkede for mig:
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>
)
};
Det er åbenlyst ret kedeligt, du kunne lægge udvidelseskoden i en anden fil som vist i eksemplet fra TypeScript-håndbogen og importere den:
import * as React from 'react';
import './react_augmented';
Men det er stadig ret beskidt. Så måske er det bedst at tage fat på problemet med bidragyderne til typedefinitionsfilen.
Svar #2
Jeg ville bruge glamors createElement-erstatning, som tilføjer en css-egenskab til hvert element.
For at tilføje til det accepterede svar ser det ud til, at modulforøgelse gør tricket, men HTMLProps virkede kun for ikke-input elementer. De korrekte interfaces at udvide ser ud til at være HTMLAttributes og SVGAttributes.
declare module 'react' {
interface HTMLAttributes<T> {
css?: any
}
interface SVGAttributes<T> {
css?: any
}
}
For at undgå at importere modulforøgelsen i hver komponent, gensend createElement:
// createElement.ts
import { createElement } from 'glamor/react'
declare module 'react' {
interface HTMLAttributes<T> {
css?: any
}
interface SVGAttributes<T> {
css?: any
}
}
export default createElement
Så fortæl TS at bruge vores createElement til JSX med denne tsconfig:
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "createElement"
}
}
Brug:
// MyComponent.tsx
import createElement from './createElement'
export default function MyComponent() {
return <div css={{ color: 'red' }} />
}
