TypeScript
不是一個高深的技術,它不過是一個javascript
的超集,那麼什麼是超集呢?
所謂的超集 其實就是最終將你寫的TypeScript
編譯成javascript
去執行,由於瀏覽器上能跑的腳本語言是javascript
,這個本質要搞清楚javascript
Javascript
缺點:沒法在編寫時察覺出同一個變量的類型是否保持一致html
好比:前端
var a = 1 //若是這個b的值是「1」,字符串 var b = "1" console.log(a+b)
結果:java
特別是ES6
以前存在全局變量,var
會給全局狀態下添加屬性以及污染全局加上ES5
的變量提高做用域等混合狀況,很容易致使變量查找時出現undefined
的問題,可是這個問題須要代碼運行才能報錯react
例如:webpack
var a; function test() { a = 1 } console.log(a) //undefined console.log(window.a)//undefined ------------------- var a; function test() { a = 1 } test() console.log(a) // 1 console.log(window.a) //1
像上面這種狀況,若是遇到了,項目很大,排查起來仍是很煩的
特別是在書寫Node.js
的時候,每每這種偏後臺類型的代碼,高併發場景出現一個小問題都是致命的,若是是一個超大型項目,排查問題起來很是困難es6
傳統的javascript
web
這段代碼,變量a
根本就沒有定義,可是根本沒有報錯,這種場景能夠在項目中多是右查詢沒有查詢到,而後輸出undefined. 但是若是是在使用這個變量去作某些事情typescript
例如: npm
這個a
變量是一個用戶很核心的數據,可是它是undefined
。而後又通過若干的類型轉換,被js
轉換成不知道是什麼的數據展現給了客戶,那麼炸了,可能會引發整個項目出現致命性錯誤直接奔潰
BUG
每每可能要浪費你們不少時間(摸魚時間)例如 :
你的同事A
寫了一個模塊,大概5個文件,一共1000行代碼
通過1000行代碼的處理,最終輸出好幾個值(變量)給了你
以下代碼:
export default { store, checkPassWord, applyMiddleWare, //.... }
一個不合格的同事 給你的沒有註釋的代碼 因而你 :
一個合格的同事:
/** @params store //數據對象 @params checkPassWord //檢查密碼函數 @params applyMiddleWare //應用中間間 */ export default { store, checkPassWord, applyMiddleWare, //.... }
若是你用到他的暴露對象內容特別多的時候,就要一個一個去看註釋,並且關鍵是:
這裏面每一個函數的傳入參數,返回的參數,註釋不必定那麼完整詳細。
那麼只有去溝通了,一旦溝通起來。時間成本上升,而且若是你們開發任務都特別緊急的時候,炸了~
TypeScript
出現了TypeScript 3.1
現已發佈
最新版本文檔地址 最新TypeScript版本文檔地址
TypeScript
並不能說是一門徹底全新的語言,能夠說它是一個基於javaScipt
的超集
什麼是超集? 其實就是原生ES6
語法+Type
類型
強烈建議閱讀阮一峯老師的 ES6入門
咱們來看下 TypeScript
的工做方式:
全局下載TypeScript
手動編譯TS
文件變成js
文件
npm install -g typescript
用全局安裝的typescript
來編譯輸出一把剛纔的文件
尚未編譯,如今已經開始報出問題,可是報出問題能夠繼續編譯嗎?
即便靜態校驗出現問題,最終仍是編譯成功:
這裏特別注意,TS
裏面的靜態類型,以及枚舉等,編譯成js
後是不存在的
上面並無體現typeScript
的特殊價值
TypeScript
的核心原則之一是對值所具備的結構進行類型檢查。 它有時被稱作「鴨式辨型法」或「結構性子類型化」。 在TypeScript
裏,接口的做用就是爲這些類型命名和爲你的代碼或第三方代碼定義契約。
//接口名爲LabelledValue interface LabelledValue { label: string; } //函數傳入的參數 labelledObj遵循 LabelledValue接口 function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label); } let myObj = {size: 10, label: "Size 10 Object"}; printLabel(myObj);
以上代碼通過ts
編譯後,全部接口和靜態類型都沒有了 :
function printLabel(labelledObj) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
若是ts
在代碼編寫階段出現了類型的校驗錯誤,那麼會直接提示:
我將接口的string
改爲了number
類型
咱們僅僅改變了接口的類型,就馬上檢驗到了錯誤,這樣沒必要等到開發模式下的熱更新調試後再報錯。
固然 你在接口定義時候,能夠在變量後加上?
號
這樣是一個可選屬性
例如:
interface SquareConfig { color?: string; width?: number; } function createSquare(config: SquareConfig): {color: string; area: number} { let newSquare = {color: "white", area: 100}; if (config.color) { newSquare.color = config.color; } if (config.width) { newSquare.area = config.width * config.width; } return newSquare; } let mySquare = createSquare({color: "black"});
還有隻讀屬性的接口定義:
interface Point { readonly x: number; readonly y: number; }
你能夠經過賦值一個對象字面量來構造一個Point。 賦值後, x和y不再能被改變了。
let p1: Point = { x: 10, y: 20 }; p1.x = 5; // error!
用得比較多的函數類型檢查
先編寫接口
interface SearchFunc { (source: string, subString: string): boolean; }
定義函數
let mySearch: SearchFunc; mySearch = function(source: string, subString: string) { let result = source.search(subString); return result > -1; }
對於函數類型的類型檢查來講,函數的參數名不須要與接口裏定義的名字相匹配。 好比,咱們使用下面的代碼重寫上面的例子:
let mySearch: SearchFunc; mySearch = function(src: string, sub: string): boolean { let result = src.search(sub); return result > -1; }
函數的參數會逐個進行檢查,要求對應位置上的參數類型是兼容的。 若是你不想指定類型,TypeScript
的類型系統會推斷出參數類型,由於函數直接賦值給了 SearchFunc類型變量。 函數的返回值類型是經過其返回值推斷出來的(此例是 false和true)。 若是讓這個函數返回數字或字符串,類型檢查器會警告咱們函數的返回值類型與 SearchFunc接口中的定義不匹配。
let mySearch: SearchFunc; mySearch = function(src, sub) { let result = src.search(sub); return result > -1; }
鴨式辨形法,說的是:一個動物長得看起來像鴨子,叫起來也像鴨子,那麼它就能夠被認爲是鴨子
定義類的類型:
interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }
一個接口能夠繼承多個接口,建立出多個接口的合成接口。
interface Shape { color: string; } interface PenStroke { penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; }
照本宣科寫了這麼多,其實這些就是TS
的最有用的地方。文檔寫得比較好,建議多去看幾遍,前提是必定要學好ES6
!
TS
中必定要儘可能避免使用any
類型any
類型有太多不可預測的後果
function identity<T>(arg: T): T { return arg; }
咱們給identity
添加了類型變量T
。 T幫助咱們捕獲用戶傳入的類型(好比:number),以後咱們就可使用這個類型。 以後咱們再次使用了 T當作返回值類型。如今咱們能夠知道參數類型與返回值類型是相同的了。 這容許咱們跟蹤函數裏使用的類型的信息。
API
能夠去刷文檔,下面說重點:typescript
趕上了webpack
React
官方推薦使用typescript
使用傳統的 react
腳手架
在 Create React App 中使用 TypeScript npx create-react-app my-app --typescript
切記 全部的ts
的依賴,都必須是@types
開頭的 不然用不了
配置tsconfig.json
文件
{ "compilerOptions": { "outDir": "./dist/", "sourceMap": true, "noImplicitAny": true, "module": "commonjs", "target": "es5", "jsx": "react" }, "include": [ "./src/**/*" ] }
npm install --save react react-dom @types/react @types/react-dom
webpack.config.js
配置文件
module.exports = { entry: "./src/index.tsx", output: { filename: "bundle.js", path: __dirname + "/dist" }, devtool: "source-map", resolve: { extensions: [".ts", ".tsx", ".js", ".json"] }, module: { rules: [ { test: /\.tsx?$/, loader: "awesome-typescript-loader" }, { enforce: "pre", test: /\.js$/, loader: "source-map-loader" } ] }, externals: { "react": "React", "react-dom": "ReactDOM" } };
你們可能對externals字段有所疑惑。 咱們想要避免把全部的React都放到一個文件裏,由於會增長編譯時間而且瀏覽器還可以緩存沒有發生改變的庫文件。
TS
最基礎關鍵的核心思想,已經介紹完了咱們不妨總結一下:
TS
最核心的優點 :
靜態類型檢查+校驗,代碼並無運行編譯,就已經知道哪裏有問題了,不管是變量查找仍是類型錯誤
TS
給咱們解決了什麼問題
減小了開發溝通成本,打開你的代碼就知道傳入的是什麼參數,返回什麼參數。編譯後代碼量並無增長
TS
給咱們帶來了什麼麻煩
多寫了不少接口,類型,一些快速開發的小項目感受用上更麻煩。若是是比較古老的js
插件第三方庫,還用不了,要另想其餘辦法去支持。
大型項目,能夠上ts
,仍是要上ts
,中小型項目,看工期,看你是否打算在時間容許狀況下嘗試使用ts
。
技術自己沒有好壞,長遠看,弱類型語言並非那麼的友好。谷歌的Go
語言,寫法就跟TypeScript
很像,若是想要擁有更廣闊的技術視野,建議前端是能夠從TS
學起,他們的思想大都差很少。
最後,歡迎你們加入咱們的segmentFault前端交流羣
,個人我的微信是:CALASFxiaotan
,加我會拉你進羣哦~
羣裏大把小姐姐等大家~
以爲寫得好,記得點個贊哦,永不脫髮