[英]Why kebab-case non-standard attributes are allowed while others aren't? And how to define types like this in TypeScript?
使用foo
作為屬性會引發錯誤:
// App.tsx
// 👇 throws
const App = () => <div foo></div>
export default App
Type '{ foo: true; }' is not assignable to type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.
Property 'foo' does not exist on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.ts(2322)
但是使用foo-foo
很好,為什么呢?
// App.tsx
// 👇 no error is thrown
const App = () => <div foo-foo></div>
export default App
最重要的是,如何在 TypeScript 中定義這樣的類型? 即只允許標准或kebab-case 屬性。
如果屬性名稱不是有效的JS 標識符(如
data-*
屬性),如果在元素屬性類型中找不到它,則不認為是錯誤。
JSX 的整個部分是一本非常有啟發性的讀物。
恐怕“如何在 TypeScript 中定義這樣的類型”問題的答案是......我們沒有。 JSX 支持內置在編譯器中。 然而,我們可以定制很多有趣的東西。
Fabio's answer中的TS手冊說明解釋了所有這些,只是想稍微擴展一下。 簡而言之,kebab-case 屬性不被 TS 認為有效但不會拋出錯誤; 但是以data-
或aria-
為前綴的屬性被認為是有效的。
React( 從 16 開始)接受自定義屬性,即<div foo />
和<div whateverYouLike={2}>
應該可以工作。
我發現 React 令人困惑的是data-*
和aria-*
應該按原樣編寫,而不是像其他所有內容一樣將它們轉換為 camelCase。 特別是當這些屬性在 vanilla DOM 中轉換為 camelCase 時:
<div data-my-age="100" aria-label="A Test" />
const $div = document.querySelector('#test')
$div.dataset.myName = "D"
console.log({ dataset: $div.dataset }) // { myAge: "100", myName: "D" }
console.log($div.ariaLabel) // "A Test"
沒有給出任何理由,所以我們只能推測。 也許與 a11y 工具、解析便利等有關。
<div foo />
在 TS 中拋出的原因是因為 TS 提供了一組嚴格的有效屬性名稱。 但是,正如另一個答案所指出的,TS 不會在random-foo
上拋出錯誤,因為它被認為是無效的 JS 標識符。 我的猜測是因為 DOM 元素允許任意屬性,所以這是一種折衷方案,允許在 TS 中的大多數情況下正確鍵入,但提供某種逃生艙口。 很想知道這些決定背后的原因。
如何在 TypeScript 中定義這樣的類型? 即只允許標准或kebab-case 屬性。
正如 Fabio 已經指出的,JSX 支持內置在編譯器中。 然而,除了識別什么構成有效屬性名稱的能力之外,我不認為它有什么神奇之處:有一個有效 DOM 屬性的綜合列表。 如果您混合使用 kebab 和 camel case,TS 不會拋出錯誤,即<div data-myName>
工作, <div myName/>
沒有,等等,所以它也不會因大小寫而有所不同。
如果您事先知道所有有效的道具,您可以模仿同樣的事情。
// allow only these prop names, which happened to be all camelCased
interface MyThing {
name: string
myName: string
anotherProp: string
}
在 kebab-case 的情況下,模板文字類型可能會有所幫助:
type ValidPrefix = "data" | "aria";
type ValidSuffix = "banana" | "apple" | "pear";
type ComputedProps = {
[key in `${ValidPrefix}-${ValidSuffix}`]?: string;
};
const x: ComputedProps = {
"data-apple": 'hi'
};
除此之外,TS 中目前沒有任何機制可以區分 camelCase 和 kebab-case 字符串。
如果您正在尋找一種方法來增強 JSX 以允許自定義道具和自定義元素,這是一種方法:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.