TypeScript——JSX(一)

介紹

JSX是一種嵌入式的類似XML的語法慧耍。 它可以被轉(zhuǎn)換成合法的JavaScript,盡管轉(zhuǎn)換的語義是依據(jù)不同的實(shí)現(xiàn)而定的滚躯。 JSX因React框架而流行胃惜,但也存在其它的實(shí)現(xiàn)。 TypeScript支持內(nèi)嵌鼎姐,類型檢查以及將JSX直接編譯為JavaScript钾麸。

基本用法

想要使用JSX必須做兩件事:

給文件一個(gè).tsx擴(kuò)展名

啟用jsx選項(xiàng)

TypeScript具有三種JSX模式:preserve,react和react-native炕桨。 這些模式只在代碼生成階段起作用 - 類型檢查并不受影響饭尝。 在preserve模式下生成代碼中會(huì)保留JSX以供后續(xù)的轉(zhuǎn)換操作使用(比如:Babel)。 另外献宫,輸出文件會(huì)帶有.jsx擴(kuò)展名钥平。 react模式會(huì)生成React.createElement,在使用前不需要再進(jìn)行轉(zhuǎn)換操作了姊途,輸出文件的擴(kuò)展名為.js涉瘾。 react-native相當(dāng)于preserve,它也保留了所有的JSX捷兰,但是輸出文件的擴(kuò)展名是.js立叛。

模式 輸入 輸出 輸出文件擴(kuò)展名

preserve <div /> <div /> .jsx

react <div /> React.createElement("div") .js

react-native <div /> <div /> .js

你可以通過在命令行里使用--jsx標(biāo)記或tsconfig.json里的選項(xiàng)來指定模式。

注意:React標(biāo)識(shí)符是寫死的硬編碼贡茅,所以你必須保證React(大寫的R)是可用的秘蛇。

as操作符

回想一下怎么寫類型斷言:

var foo = <foo>bar;

這里斷言bar變量是foo類型的。 因?yàn)門ypeScript也使用尖括號(hào)來表示類型斷言友扰,在結(jié)合JSX的語法后將帶來解析上的困難彤叉。因此,TypeScript在.tsx文件里禁用了使用尖括號(hào)的類型斷言村怪。

由于不能夠在.tsx文件里使用上述語法秽浇,因此我們應(yīng)該使用另一個(gè)類型斷言操作符:as。 上面的例子可以很容易地使用as操作符改寫:

var foo = bar as foo;

as操作符在.ts和.tsx里都可用甚负,并且與尖括號(hào)類型斷言行為是等價(jià)的柬焕。

類型檢查

為了理解JSX的類型檢查,你必須首先理解固有元素與基于值的元素之間的區(qū)別梭域。 假設(shè)有這樣一個(gè)JSX表達(dá)式<expr />斑举,expr可能引用環(huán)境自帶的某些東西(比如,在DOM環(huán)境里的div或span)或者是你自定義的組件病涨。 這是非常重要的富玷,原因有如下兩點(diǎn):

對(duì)于React,固有元素會(huì)生成字符串(React.createElement("div")),然而由你自定義的組件卻不會(huì)生成(React.createElement(MyComponent))赎懦。

傳入JSX元素里的屬性類型的查找方式不同雀鹃。 固有元素屬性本身就支持,然而自定義的組件會(huì)自己去指定它們具有哪個(gè)屬性励两。

TypeScript使用與React相同的規(guī)范 來區(qū)別它們黎茎。 固有元素總是以一個(gè)小寫字母開頭,基于值的元素總是以一個(gè)大寫字母開頭当悔。

固有元素

固有元素使用特殊的接口JSX.IntrinsicElements來查找傅瞻。 默認(rèn)地,如果這個(gè)接口沒有指定盲憎,會(huì)全部通過嗅骄,不對(duì)固有元素進(jìn)行類型檢查。 然而焙畔,如果這個(gè)接口存在掸读,那么固有元素的名字需要在JSX.IntrinsicElements接口的屬性里查找。 例如:

declare namespace JSX {

? ? interface IntrinsicElements {

? ? ? ? foo: any

? ? }

}

<foo />; // 正確

<bar />; // 錯(cuò)誤

在上例中宏多,<foo />沒有問題儿惫,但是<bar />會(huì)報(bào)錯(cuò),因?yàn)樗鼪]在JSX.IntrinsicElements里指定伸但。

注意:你也可以在JSX.IntrinsicElements上指定一個(gè)用來捕獲所有字符串索引:

declare namespace JSX {

? ? interface IntrinsicElements {

? ? ? ? [elemName: string]: any;

? ? }

}

基于值的元素

基于值的元素會(huì)簡(jiǎn)單的在它所在的作用域里按標(biāo)識(shí)符查找肾请。

import MyComponent from "./myComponent";


<MyComponent />; // 正確

<SomeOtherComponent />; // 錯(cuò)誤

有兩種方式可以定義基于值的元素:

無狀態(tài)函數(shù)組件 (SFC)

類組件

由于這兩種基于值的元素在JSX表達(dá)式里無法區(qū)分,因此TypeScript首先會(huì)嘗試將表達(dá)式做為無狀態(tài)函數(shù)組件進(jìn)行解析更胖。如果解析成功铛铁,那么TypeScript就完成了表達(dá)式到其聲明的解析操作。如果按照無狀態(tài)函數(shù)組件解析失敗却妨,那么TypeScript會(huì)繼續(xù)嘗試以類組件的形式進(jìn)行解析饵逐。如果依舊失敗,那么將輸出一個(gè)錯(cuò)誤彪标。

無狀態(tài)函數(shù)組件

正如其名倍权,組件被定義成JavaScript函數(shù),它的第一個(gè)參數(shù)是props對(duì)象捞烟。 TypeScript會(huì)強(qiáng)制它的返回值可以賦值給JSX.Element薄声。

interface FooProp {

? ? name: string;

? ? X: number;

? ? Y: number;

}

declare function AnotherComponent(prop: {name: string});

function ComponentFoo(prop: FooProp) {

? ? return <AnotherComponent name={prop.name} />;

}

const Button = (prop: {value: string}, context: { color: string }) => <button>

由于無狀態(tài)函數(shù)組件是簡(jiǎn)單的JavaScript函數(shù),所以我們還可以利用函數(shù)重載题画。

interface ClickableProps {

? ? children: JSX.Element[] | JSX.Element

}

interface HomeProps extends ClickableProps {

? ? home: JSX.Element;

}

interface SideProps extends ClickableProps {

? ? side: JSX.Element | string;

}

function MainButton(prop: HomeProps): JSX.Element;

function MainButton(prop: SideProps): JSX.Element {

? ? ...

}

類組件

我們可以定義類組件的類型默辨。 然而,我們首先最好弄懂兩個(gè)新的術(shù)語:元素類的類型和元素實(shí)例的類型苍息。

現(xiàn)在有<Expr />缩幸,元素類的類型為Expr的類型壹置。 所以在上面的例子里,如果MyComponent是ES6的類表谊,那么類類型就是類的構(gòu)造函數(shù)和靜態(tài)部分蒸绩。 如果MyComponent是個(gè)工廠函數(shù),類類型為這個(gè)函數(shù)铃肯。

一旦建立起了類類型,實(shí)例類型由類構(gòu)造器或調(diào)用簽名(如果存在的話)的返回值的聯(lián)合構(gòu)成传蹈。 再次說明押逼,在ES6類的情況下,實(shí)例類型為這個(gè)類的實(shí)例的類型惦界,并且如果是工廠函數(shù)挑格,實(shí)例類型為這個(gè)函數(shù)返回值類型。

class MyComponent {

? ? render() {}

}

// 使用構(gòu)造簽名

var myComponent = new MyComponent();

// 元素類的類型 => MyComponent

// 元素實(shí)例的類型 => { render: () => void }

function MyFactoryFunction() {

? ? return {

? ? render: () => {

? ? }

? ? }

}

// 使用調(diào)用簽名

var myComponent = MyFactoryFunction();

// 元素類的類型 => FactoryFunction

// 元素實(shí)例的類型 => { render: () => void }

元素的實(shí)例類型很有趣沾歪,因?yàn)樗仨氋x值給JSX.ElementClass或拋出一個(gè)錯(cuò)誤漂彤。 默認(rèn)的JSX.ElementClass為{},但是它可以被擴(kuò)展用來限制JSX的類型以符合相應(yīng)的接口灾搏。

declare namespace JSX {

? ? interface ElementClass {

? ? render: any;

? ? }

}

class MyComponent {

? ? render() {}

}

function MyFactoryFunction() {

? ? return { render: () => {} }

}

<MyComponent />; // 正確

<MyFactoryFunction />; // 正確

class NotAValidComponent {}

function NotAValidFactoryFunction() {

? ? return {};

}

<NotAValidComponent />; // 錯(cuò)誤

<NotAValidFactoryFunction />; // 錯(cuò)誤

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末挫望,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狂窑,更是在濱河造成了極大的恐慌媳板,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泉哈,死亡現(xiàn)場(chǎng)離奇詭異蛉幸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丛晦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門奕纫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人烫沙,你說我怎么就攤上這事匹层。” “怎么了斧吐?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵又固,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我煤率,道長(zhǎng)仰冠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任蝶糯,我火速辦了婚禮洋只,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己识虚,他們只是感情好肢扯,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著担锤,像睡著了一般蔚晨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肛循,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天铭腕,我揣著相機(jī)與錄音,去河邊找鬼多糠。 笑死累舷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的夹孔。 我是一名探鬼主播被盈,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼搭伤!你這毒婦竟也來了只怎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤怜俐,失蹤者是張志新(化名)和其女友劉穎尝盼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佑菩,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盾沫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了殿漠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赴精。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绞幌,靈堂內(nèi)的尸體忽然破棺而出蕾哟,到底是詐尸還是另有隱情,我是刑警寧澤莲蜘,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布谭确,位于F島的核電站,受9級(jí)特大地震影響票渠,放射性物質(zhì)發(fā)生泄漏逐哈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一问顷、第九天 我趴在偏房一處隱蔽的房頂上張望昂秃。 院中可真熱鬧禀梳,春花似錦、人聲如沸肠骆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚀腿。三九已至嘴瓤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間莉钙,已是汗流浹背纱注。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胆胰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓刻获,卻偏偏與公主長(zhǎng)得像蜀涨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蝎毡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 以下內(nèi)容是我在學(xué)習(xí)和研究React時(shí)厚柳,對(duì)React的特性、重點(diǎn)和注意事項(xiàng)的提取沐兵、精練和總結(jié)别垮,可以做為React特性...
    科研者閱讀 8,219評(píng)論 2 21
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過程中的一些閱讀筆記扎谎,個(gè)人覺得該教程講解深入淺出碳想,比目前大...
    leonaxiong閱讀 2,810評(píng)論 1 18
  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,048評(píng)論 2 35
  • 3. JSX JSX是對(duì)JavaScript語言的一個(gè)擴(kuò)展語法, 用于生產(chǎn)React“元素”毁靶,建議在描述UI的時(shí)候...
    pixels閱讀 2,806評(píng)論 0 24
  • 轉(zhuǎn)發(fā) TypeScript基礎(chǔ)入門之JSX(一) 介紹 JSX是一種可嵌入的類似XML的語法胧奔。 它旨在轉(zhuǎn)換為有效...
    鵬鯤云之上閱讀 16,276評(píng)論 0 1