鍍金池/ 教程/ HTML/ 介紹
初始化項目結構
聯(lián)合類型
介紹
介紹
介紹
編譯選項
TypeScript 1.6
介紹
介紹
發(fā)展路線圖
介紹
在MSBuild里使用編譯選項
可迭代性
TypeScript 1.3
介紹
介紹
TypeScript 1.1
變量聲明
即將到來的Angular 2框架是使用TypeScript開發(fā)的。 因此Angular和TypeScript一起使用非常簡單方便
tsconfig.json
介紹
介紹
介紹
在MSBuild里使用編譯選項
使用TypeScript的每日構建版本
新建工程
枚舉
三斜線指令
結合ASP.NET v5使用TypeScript
TypeScript里的this
介紹
TypeScript 1.4
編碼規(guī)范
介紹
模塊解析
ASP.NET 4
架構概述
介紹
介紹
ASP.NET Core
TypeScript 1.8
介紹
介紹
創(chuàng)建簡單工程
TypeScript 1.7
TypeScript 1.5
NPM包的類型
支持TypeScript的編輯器

介紹

JSX是一種嵌入式的類似XML的語法。 它可以被轉(zhuǎn)換成合法的JavaScript,盡管轉(zhuǎn)換的語義是依據(jù)不同的實現(xiàn)而定的。 JSX因React框架而流行,但是也被其它應用所使用。 TypeScript支持內(nèi)嵌,類型檢查和將JSX直接編譯為JavaScript。

基本用法

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

  1. 給文件一個.tsx擴展名
  2. 啟用jsx選項

TypeScript具有兩種JSX模式:preservereact。 這些模式只在代碼生成階段起作用 - 類型檢查并不受影響。 在preserve模式下生成代碼中會保留JSX以供后續(xù)的轉(zhuǎn)換操作使用(比如:Babel)。 另外,輸出文件會帶有.jsx擴展名。 react模式會生成React.createElement,在使用前不需要再進行轉(zhuǎn)換操作了,輸出文件的擴展名為.js。

模式 輸入 輸出 輸出文件擴展名
preserve <div /> <div /> .jsx
react <div /> React.createElement("div") .js

你可以通過在命令行里使用--jsx標記或tsconfig.json里的選項來指定模式。

注意:React標識符是寫死的硬代碼,所以你必須保證React(大寫的R)是可用的。 Note: The identifier React is hard-coded, so you must make React available with an uppercase R.

as操作符

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

var foo = <foo>bar;

這里我們斷言bar變量是foo類型的。 因為TypeScript也使用尖括號來表示類型斷言,JSX的語法帶來了解析的困難。因此,TypeScript在.tsx文件里禁用了使用尖括號的類型斷言。

為了彌補.tsx里的這個功能,新加入了一個類型斷言符號:as。 上面的例子可以很容易地使用as操作符改寫:

var foo = bar as foo;

as操作符在.ts.tsx里都可用,并且與其它類型斷言行為是等價的。

類型檢查

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

  1. 對于React,固有元素會生成字符串(React.createElement("div")),然而由你自定義的組件卻不會生成(React.createElement(MyComponent))。
  2. 傳入JSX元素里的屬性類型的查找方式不同。 固有元素屬性本身就支持,然而自定義的組件會自己去指定它們具有哪個屬性。

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

固有元素

固有元素使用特殊的接口JSX.IntrinsicElements來查找。 默認地,如果這個接口沒有指定,會全部通過,不對固有元素進行類型檢查。 然而,如果接口存在,那么固有元素的名字需要在JSX.IntrinsicElements接口的屬性里查找。 例如:

declare namespace JSX {
    interface IntrinsicElements {
        foo: any
    }
}

<foo />; // 正確
<bar />; // 錯誤

在上例中,<foo />沒有問題,但是<bar />會報錯,因為它沒在JSX.IntrinsicElements里指定。

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

declare namespace JSX {
   interface IntrinsicElements {
       [elemName: string]: any;
   }
}

基于值的元素

基于值的元素會簡單的在它所在的作用域里按標識符查找。

import MyComponent from "./myComponent";

<MyComponent />; // 正確
<SomeOtherComponent />; // 錯誤

可以限制基于值的元素的類型。 然而,為了這么做我們需要引入兩個新的術語:元素類的類型元素實例的類型

現(xiàn)在有<Expr />,元素類的類型Expr的類型。 所以在上面的例子里,如果MyComponent是ES6的類,那么它的類類型就是這個類。 如果MyComponent是個工廠函數(shù),類類型為這個函數(shù)。

一旦建立起了類類型,實例類型就確定了,為類類型調(diào)用簽名的返回值與構造簽名的聯(lián)合類型。 再次說明,在ES6類的情況下,實例類型為這個類的實例的類型,并且如果是工廠函數(shù),實例類型為這個函數(shù)返回值類型。

class MyComponent {
  render() {}
}

// 使用構造簽名
var myComponent = new MyComponent();

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

function MyFactoryFunction() {
  return {
    render: () => {
    }
  }
}

// 使用調(diào)用簽名
var myComponent = MyFactoryFunction();

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

元素的實例類型很有趣,因為它必須賦值給JSX.ElementClass或拋出一個錯誤。 默認的JSX.ElementClass{},但是它可以被擴展用來限制JSX的類型以符合相應的接口。

declare namespace JSX JSX {
  interface ElementClass {
    render: any;
  }
}

class MyComponent {
  render() {}
}
function MyFactoryFunction() {
  return { render: () => {} }
}

<MyComponent />; // 正確
<MyFactoryFunction />; // 正確

class NotAValidComponent {}
function NotAValidFactoryFunction() {
  return {};
}

<NotAValidComponent />; // 錯誤
<NotAValidFactoryFunction />; // 錯誤

屬性類型檢查

屬性類型檢查的第一步是確定元素屬性類型。 這在固有元素和基于值的元素之間稍有不同。

對于固有元素,這是JSX.IntrinsicElements屬性的類型。

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

// `foo`的元素屬性類型為`{bar?: boolean}`
<foo bar />;

對于基于值的元素,就稍微復雜些。 它取決于先前確定的在元素實例類型上的某個屬性的類型。 至于該使用哪個屬性來確定類型取決于JSX.ElementAttributesProperty。 它應該使用單一的屬性來定義。 這個屬性名之后會被使用。

declare namespace JSX {
  interface ElementAttributesProperty {
    props; // 指定用來使用的屬性名
  }
}

class MyComponent {
  // 在元素實例類型上指定屬性
  props: {
    foo?: string;
  }
}

// `MyComponent`的元素屬性類型為`{foo?: string}`
<MyComponent foo="bar" />

元素屬性類型用于的JSX里進行屬性的類型檢查。 支持可選屬性和必須屬性。

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

<foo requiredProp="bar" />; // 正確
<foo requiredProp="bar" optionalProp={0} />; // 正確
<foo />; // 錯誤, 缺少 requiredProp
<foo requiredProp={0} />; // 錯誤, requiredProp 應該是字符串
<foo requiredProp="bar" unknownProp />; // 錯誤, unknownProp 不存在
<foo requiredProp="bar" some-unknown-prop />; // 正確, `some-unknown-prop`不是個合法的標識符

注意:如果一個屬性名不是個合法的JS標識符(像data-*屬性),并且它沒出現(xiàn)在元素屬性類型里時不會當做一個錯誤。

延展操作符也可以使用:

var props = { requiredProp: 'bar' };
<foo {...props} />; // 正確

var badProps = {};
<foo {...badProps} />; // 錯誤

JSX結果類型

默認地JSX表達式結果的類型為any。 你可以自定義這個類型,通過指定JSX.Element`接口。 然而,不能夠從接口里檢索元素,屬性或JSX的子元素的類型信息。 它是一個黑盒。

嵌入的表達式

JSX允許你使用{ }標簽來內(nèi)嵌表達式。

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

上面的代碼產(chǎn)生一個錯誤,因為你不能用數(shù)字來除以一個字符串。 輸出如下,若你使用了preserve選項:

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

React整合

要想一起使用JSX和React,你應該使用React類型定義。 這些類型聲明定義了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" />; // 正確
<MyComponent foo={0} />; // 錯誤
上一篇:介紹下一篇:發(fā)展路線圖