TypeScript基礎(chǔ)入門之JSX(二)

轉(zhuǎn)發(fā) TypeScript基礎(chǔ)入門之JSX(二)

屬性類型檢查

鍵入檢查屬性的第一步是確定元素屬性類型。
內(nèi)在元素和基于價值的元素之間略有不同。

對于內(nèi)部元素,它是JSX.IntrinsicElements上的屬性類型

declare namespace JSX {
  interface IntrinsicElements {
    foo: { bar?: boolean }
  }
}

// element attributes type for 'foo' is '{bar?: boolean}'
<foo bar />;

對于基于價值的元素,它有點(diǎn)復(fù)雜。
它由先前確定的元素實(shí)例類型上的屬性類型確定。
使用哪個屬性由JSX.ElementAttributesProperty確定。
它應(yīng)該用單個屬性聲明。
然后使用該屬性的名稱。
從TypeScript 2.8開始,如果未提供JSX.ElementAttributesProperty,則將使用類元素的構(gòu)造函數(shù)或SFC調(diào)用的第一個參數(shù)的類型。

declare namespace JSX {
  interface ElementAttributesProperty {
    props; // specify the property name to use
  }
}

class MyComponent {
  // specify the property on the element instance type
  props: {
    foo?: string;
  }
}

// element attributes type for 'MyComponent' is '{foo?: string}'
<MyComponent foo="bar" />

元素屬性類型用于鍵入檢查JSX中的屬性。
支持可選和必需的屬性。

declare namespace JSX {
  interface IntrinsicElements {
    foo: { requiredProp: string; optionalProp?: number }
  }
}

<foo requiredProp="bar" />; // ok
<foo requiredProp="bar" optionalProp={0} />; // ok
<foo />; // error, requiredProp is missing
<foo requiredProp={0} />; // error, requiredProp should be a string
<foo requiredProp="bar" unknownProp />; // error, unknownProp does not exist
<foo requiredProp="bar" some-unknown-prop />; // ok, because 'some-unknown-prop' is not a valid identifier

注意:如果屬性名稱不是有效的JS標(biāo)識符(如data-*屬性),則如果在元素屬性類型中找不到它,則不會將其視為錯誤。

此外,JSX.IntrinsicAttributes接口可用于指定JSX框架使用的額外屬性,這些屬性通常不被組件的props或參數(shù)使用 - 例如React中的鍵。
進(jìn)一步說,通用JSX.IntrinsicClassAttributes <T>類型也可用于為類組件(而不是SFC)指定相同類型的額外屬性。
在此類型中,泛型參數(shù)對應(yīng)于類實(shí)例類型。
在React中,這用于允許類型為Ref <T>的ref屬性。
一般來說,這些接口上的所有屬性都應(yīng)該是可選的,除非您打算讓JSX框架的用戶需要在每個標(biāo)記上提供一些屬性。
擴(kuò)展操作符也是有效的:

var props = { requiredProp: "bar" };
<foo {...props} />; // ok

var badProps = {};
<foo {...badProps} />; // error

子類型檢查

在TypeScript 2.3中,TS引入了子類型檢查。
children是元素屬性類型中的特殊屬性,其中子JSXExpressions被插入到屬性中。
類似于TS使用JSX.ElementAttributesProperty來確定props的名稱,TS使用JSX.ElementChildrenAttribute來確定這些props中的子項(xiàng)名稱。
應(yīng)使用單個屬性聲明JSX.ElementChildrenAttribute。

declare namespace JSX {
  interface ElementChildrenAttribute {
    children: {};  // specify children name to use
  }
}
<div>
  <h1>Hello</h1>
</div>;

<div>
  <h1>Hello</h1>
  World
</div>;

const CustomComp = (props) => <div>props.children</div>
<CustomComp>
  <div>Hello World</div>
  {"This is just a JS expression..." + 1000}
</CustomComp>

您可以像任何其他屬性一樣指定子類型。
這將覆蓋默認(rèn)類型,例如React typings(如果您使用它們)。

interface PropsType {
  children: JSX.Element
  name: string
}

class Component extends React.Component<PropsType, {}> {
  render() {
    return (
      <h2>
        {this.props.children}
      </h2>
    )
  }
}

// OK
<Component>
  <h1>Hello World</h1>
</Component>

// Error: children is of type JSX.Element not array of JSX.Element
<Component>
  <h1>Hello World</h1>
  <h2>Hello World</h2>
</Component>

// Error: children is of type JSX.Element not array of JSX.Element or string.
<Component>
  <h1>Hello</h1>
  World
</Component>

JSX結(jié)果類型

默認(rèn)情況下,JSX表達(dá)式的結(jié)果鍵入為any。您可以通過指定JSX.Element接口來自定義類型。但是,無法從此接口檢索有關(guān)JSX的元素,屬性或子級的類型信息。這是一個黑盒子。

嵌入表達(dá)式

JSX允許您通過用大括號({})包圍表達(dá)式來在標(biāo)記之間嵌入表達(dá)式。

var a = <div>
  {["foo", "bar"].map(i => <span>{i / 2}</span>)}
</div>

上面的代碼將導(dǎo)致錯誤,因?yàn)槟荒軐⒆址詳?shù)字。
使用preserve選項(xiàng)時,輸出如下所示:

var a = <div>
  {["foo", "bar"].map(function (i) { return <span>{i / 2}</span>; })}
</div>

React整合

要將JSX與React一起使用,您應(yīng)該使用React類型。
這些類型適當(dāng)?shù)囟x了JSX名稱空間以與React一起使用。

/// <reference path="react.d.ts" />

interface Props {
  foo: string;
}

class MyComponent extends React.Component<Props, {}> {
  render() {
    return <span>{this.props.foo}</span>
  }
}

<MyComponent foo="bar" />; // ok
<MyComponent foo={0} />; // error

工廠函數(shù)

jsx:react編譯器選項(xiàng)使用的確切工廠函數(shù)是可配置的。
可以使用jsxFactory命令行選項(xiàng)或內(nèi)聯(lián)@jsx注釋編譯指示來設(shè)置它以基于每個文件進(jìn)行設(shè)置。
例如,如果將jsxFactory設(shè)置為createElement,則<div />將作為createElement("div")而不是React.createElement("div")來編譯。

注釋pragma版本可以像這樣使用(在TypeScript 2.8中):

import preact = require("preact");
/* @jsx preact.h */
const x = <div />;

編譯為

const preact = require("preact");
const x = preact.h("div", null);

選擇的工廠也將影響JSX命名空間的查找位置(用于類型檢查信息),然后再回退到全局命名空間。
如果工廠定義為React.createElement(默認(rèn)值),編譯器將在檢查全局JSX之前檢查React.JSX。
如果工廠定義為h,它將在全局JSX之前檢查h.JSX。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容