2016-10-17 10 views
10

Ktoś wie, jak prawidłowo dodać/rozszerzyć wszystkie natywne atrybuty elementu HTML, używając niestandardowych?Jak dodać atrybuty do istniejących elementów HTML w TypeScript/JSX?

Z the TypeScript documentation for merging interfaces, myślałem, że może po prostu to zrobić:

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

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

Ale pojawia się następujący błąd Intellisense w vscode 1.6.1 (najnowsza):

[ts] Własność ' blok "nie istnieje w typie" HTMLProps ".

HTMLProps do których się odnosimy jest React.HTMLProps<T> i element div deklaruje go używać tak:

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

Próbowałem redeclaring się div, ale bezskutecznie.

pokrewne: https://github.com/Microsoft/TypeScript/issues/11684

Edit: Oto, co skończyło się dla mnie praca:

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

@MadaraUchiha Co powiesz na 'extend'ing' React.HTMLProps '? Lub nawet łączenie deklaracji z 'React.HTMLProps '? –

+0

@ZevSpitz Próbowałem obu, a oni nie działali dobrze. Rozszerzanie nie pomaga, ponieważ nie mogę zmusić go do użycia mojego interfejsu, użyje po prostu 'React.HTMLProps ', a scalanie deklaracji po prostu nie zadziałało, całkowicie je zignorowało. Jeśli możesz zrobić przypadek, w którym to działa, rozważ umieszczenie go jako odpowiedzi. –

+0

@MadaraUchiha _merging deklaracji po prostu nie działał. Zakładam, że masz na myśli 'przestrzeń nazw React {interfejs HTMLProps {/ * niestandardowe elementy tutaj * /}}'? Nie wiem, jak wygląda deklaracja 'HTMLProps', może być konieczne dopasowanie jej. –

Odpowiedz

3

Wygląda jak w starszych wersjach plików definicji typu (v0.14) interfejsy po prostu deklarowanych pod globalna przestrzeń nazw React, więc wcześniej można było użyć standardowej składni scalającej.

declare namespace React { 

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

Jednak nowa wersja pliku d.ts (v15.0) zadeklarowała wszystko w module. Ponieważ moduły nie obsługują połączenia, do mojej najlepszej wiedzy, jedynym rozwiązaniem wydaje się teraz być module augmentation: https://www.typescriptlang.org/docs/handbook/declaration-merging.html

zrobiłem następujący eksperyment i pracował dla mnie:

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

Oczywiście jest to dość uciążliwe, można umieścić kod powiększania w innym pliku, jak pokazano w przykładzie z podręcznika maszynopis, a następnie zaimportować go:

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

Ale to wciąż bardzo brudna. Więc może najlepiej rozwiązać problem z autorami pliku definicji typu.

+1

Dziękujemy! W międzyczasie rozwiązaliśmy ten problem w inny sposób, ale jest to szczegółowa odpowiedź ze wszystkim, co jest potrzebne, aby rozwiązać pytanie, ponieważ zostało zadane. Masz moje +1 i nagrodę. Dobra robota! :) –

2

Chciałem użyć zamiennika Glamour createElement, który dodaje do każdego elementu propozycję css.

Aby dodać do zaakceptowanej odpowiedzi, augmentacja modułu wydaje się być skuteczna, ale HTMLProps działa tylko dla elementów nie-wejściowych. Poprawne interfejsy do rozszerzenia wydają się być HTMLAttributes i SVGAttributes.

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

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

Aby uniknąć importowania powiększania modułu w każdym składniku, createElement reeksport:

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

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

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

export default createElement 

Wtedy powiedzieć TS do korzystania z naszego createElement dla JSX z tym tsconfig:

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

Usage :

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

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