TS => TypeScript:2012/10由微軟開發,是一個開源的、跨平臺且帶有類型系統的JS(ES6/7)超集,它能夠編譯爲純JS,而後運行在任意的瀏覽器和其餘環境。html
TS是爲大型應用之開發而設計,它添加了可選的靜態類型、類和模塊,讓大型JS應用可使用更好的工具並擁有更清晰的結構,目前最新版本:3.1。vue
相似的語言flow,facebook出品,react/vue2源碼在使用, vue3小尤也規劃用TS重構。node
vue2部分源碼,摘自:vuesrccoreobserverwatcher.js:
/* @flow */ export default class Watcher { vm: Component; expression: string; cb: Function; id: number; deep: boolean; ... deps: Array<Dep>; newDeps: Array<Dep>; depIds: SimpleSet; newDepIds: SimpleSet; getter: Function; value: any; constructor ( vm: Component, expOrFn: string | Function, cb: Function, options?: ?Object, isRenderWatcher?: boolean ) ...
JS的痛點:react
弱類型
沒有面向對象的接口規範
沒有命名空間
沒有跨文件邏輯預編譯能力
TS的收益:webpack
a.) 更多的規則和類型限制 => 讓代碼預測性更高,可控性更高,易於維護和調試。es6
b.) 對模塊、命名空間和麪向對象的支持 => 更容易組織代碼開發大型複雜程序。web
c.) 更多的語法糖:類,接口,枚舉,泛型,方法重載 => 用簡潔的語法豐富了JavaScript的使用。typescript
d.) TS強大的靜態編譯/IDE支持 => 類型檢測、語法提示,能夠捕獲運行以前的錯誤。express
$ npm i -g typescript $ tsc -v
$ tsc test.ts // 逐個編譯 $ tsc *.tsx // 批量編譯, tsx是jsx類型的文件 $ tsc test.ts --watch // 實時監控,自動編譯
基本類型npm
let name: string = 'tom' let age: number = 8 let success: boolean = true // 聯合類型 let x: number | string x = 1 x = 'ok'
數組
let arr: number[] = [1, 2] let arr: Array<number> = [1, 2] // 範型寫法 // 只讀數組,全部可變方法都被移除了 let arr: ReadonlyArray<number> = [1, 2] arr.splice(1, 'x') // Error // 元組 Tuple let arr: [number, string] = [1, 'ok']
枚舉
enum類型是對JS標準數據類型的一個補充
enum Direction{ Up = 1, Down, Left, Right } let c: Color = Direction.Left // 3
數字枚舉有自增加的特性,字符串枚舉需初始化字面量
Any
不指定類型,任意類型,相似js弱類型
let arg: any = 1 let arr: any[] = [1, 'ok', false]
Void
void類型像是與any類型相反,表示沒有任何類型
function test(arg: string): void { // ... }
Null/Undefined
默認狀況下null和undefined是全部類型的子類型
let u: undefined = undefined let n: null = null // 對象? 引用類型? 堆?
Never
never類型表示的是那些永不存在的值的類型,經常使用定義報錯回調和無限循環的返回值
never類型也是任何類型的子類型,也能夠賦值給任何類型
function fail(msg: string): never { throw new Error(msg); }
泛型
簡單的講就是用戶傳一個類型的參數,指望獲得相同類型的返回值
function identity<T>(arg: T): T { return arg } let idx1: number = identity(11) let idx2: string = identity(11) // Error
交叉類型
交叉類型,就是將多個類型合併爲一個新的類型,相似於繼承
function extend<T, U>(first: T, second: U): T & U { let result = <T & U>{} for (let key in first) { (<any>result)[key] = (<any>first)[key] } for (let key in second) { if (!result.hasOwnProperty(key)) { (<any>result)[key] = (<any>second)[key] } } return result }
TS的核心原則之一是對值所具備的結構進行類型檢查,與外界規範化對象參數
interface Animal { name: string age?: number // 可選屬性 readonly sex: string // 只讀屬性 } function test(arg: Animal) { arg.sex = 'female' // Error,不能賦值 } test({name: 'tom', sex: 'male'}})
接口繼承
能夠繼承多個接口
interface Cat extends Animal1, Animal2 { friend: string }
函數類型
接口中定義了相似一個只有形數列表和返回值類型的函數
interface Cat { (name: string, age: number): void } let cat: Cat = function(n: string, a: number) { console.log(...arguments) }
類類型
顯式地強制一個類知足一個特定的契約。關鍵字implements
interface ClockInterface { current: Date setTime(d: Date) } class Clock implements ClockInterface { current: Date setTime(d: Date) { this.current = d } constructor(h: number, m: number) {} }
接口描述了類的公共的部分,而不是公共和私有兩部分。這會阻止你使用它們來檢查一個類的實例的私有部分也有特定的類型。
ts增長了四種修飾符:public、private、protected、readonly
private: 僅本身用,不能被繼承,外部不可用
protected: 派生類可繼承,外部不可用
readonly: 只讀
class Animal { public name: string private age: number protected sex: string readonly family: string constructor(arg: any) { this.name = arg.name } } class Cat extends Animal { constructor(arg: any) { super(arg) this.name = arg.name this.age = arg.age // 派生類不能繼承私有屬性 this.sex = arg.sex // OK this.family = 'cat' // Err,只讀 } } let cat = new Cat({ name: 'tom', age: 8, sex: 'male' }) console.log(cat.age) // Err,私有屬性不外放 console.log(cat.sex) // Err,保護屬性不能在類外訪問
抽象類作爲派生類的基類使用,通常不會直接被實例化,抽象類中的抽象方法也需在派生類中實現
abstract class Animal { public name: string abstract setName(name: string): void // 必須在派生類中實現 } class Cat extends Animal { constructor(name: string) { super() } setName(name: string) { this.name = name } } let cat = new Cat('tom')
傳統的模塊是指外部模塊(文件),「內部模塊」稱做命名空間,使用 namespace關鍵字
// namespace1.js namespace ValidSpace { const name = 'tom' export const sex = 'male' export interface ValidCat { (s: string): boolean } } interface myValid extends ValidSpace.ValidCat { name: string } console.log(ValidSpace.name) // Error console.log(ValidSpace.sex)
一個命名空間能夠分散到多個文件中,訪問時如同一個文件,全部內容共享。
經過三斜線指令///,告訴編譯器在編譯過程當中要引入的額外的文件
/// <reference path="./namespace1.ts" /> namespace ValidSpace { export interface Cat extends ValidCat {} // 另外一個文件同名空間的接口 console.log(sex) // OK }
命名空間能夠嵌套,當引用目錄很深時可使用關鍵字import簡化別名,如:import q = x.y.z
namespace Shapes { export namespace Polygons { export class Triangle {} export class Square {} } } import polygons = Shapes.Polygons; let sq = new polygons.Square()
import會生成與原始符號不一樣的引用,因此改變別名的值並不會影響原始變量的值。
當一些全局的公共的環境變量不被認識時,能夠用declare操做符建立一個環境聲明。
聲明變量文件通常以x.d.ts結尾的文件。
interface CustomConsole { log(arg : string) : void } declare let customConsole : CustomConsole customConsole.log('試試') // 成功
TS默認包含一個名爲lib.d.ts的文件,聲明瞭DOM(文檔對象模型),還有BOM(瀏覽器對象模型)全局變量,無須本身聲明瞭。
webpack須要添加ts相關的loader,webpack3.x最大支持ts-loader@3.5.0
$ npm i typescript ts-loader@3.5.0 -D
若是是react項目還須要一些必要的類型庫
$ npm i @types/react @types/react-dom @types/styled-components
eslint添加typescript插件安裝
$ npm i typescript-eslint-parser eslint-plugin-typescript -D
.eslint.js配置
module.exports = { "root": true, "parser": "typescript-eslint-parser", "plugins": [ "typescript" ], "parserOptions": { "ecmaVersion": 6, "ecmaFeatures": { "jsx": true // 啓用JSX } }, ...
$ tsc --init
ts相關配置:
{ "compilerOptions": { "target": "es6", "module": "commonjs", "allowJs": true, // 能夠混合開發 "jsx": "react", "sourceMap": true, "strict": true, "baseUrl": "./", "paths": { "@/*": ["./src/*"], "assets/*": ["./src/assets/*"], "components/*": ["./src/components/*"], "config/*": ["./src/config/*"], "libs/*": ["./src/libs/*"], "module/*": ["./src/module/*"], "store/*": ["./src/store/*"] }, // "typeRoots": [], // "types": [], "esModuleInterop": true, "experimentalDecorators": true }, "exclude": [ "node_modules" ] }