摘要:要為變量或者常量指定類型也很簡單,就是在變量常量名后面加個冒號,再指定類型即可,比如聲明函數(shù)是類型,即返回值是類型聲明參數(shù)是類型聲明是無返回值的聲明是這段代碼演示了對函數(shù)類型參數(shù)類型和變量類型地聲明。變量函數(shù)參數(shù)和返回值需要申明類型。
從 JavaScript 語法改寫為 TypeScript 語法,有兩個關(guān)鍵點,一點是類成員變量(Field)需要聲明,另一點是要為各種東西(變量、參數(shù)、函數(shù)/方法等)聲明類型。而這兩個點直接引出了兩個關(guān)鍵性的問題,有哪些類型?怎樣聲明?
類型在說 TypeScript 的類型之前,我們先復(fù)習(xí)一下 JavaScript 的七種類型:
undefined
function
boolean
number
string
object
symbol
這七種類型都是可以通過 typeof 運算符算出來的,但其中并沒有我們常見的 Array、null,Date 之類的類型——因為它們其實都是 object。
TypeScript 的重要特性之一就是類型,所以 TypeScript 中的類型要講究得多,除了 JavaScript 中的類型之外,還定義了其它一些(不完全列表)
Array
null,空類型,其作用與 strictNullChecks 編譯參數(shù)有關(guān)
Tuple(元組),形如 [Number, String]
enum T,定義枚舉類型 T,可理解為集中對數(shù)值常量進行命名
interface T,接口,T 是一種接口類型
class T,類,T 是一種類型
any,代表任意類型
void,表示沒有類型,用于聲明函數(shù)類型
never,表示函數(shù)不可返回的神奇類型
……
具體的類型這里就不詳述了,官方 Handbook 的 Basic Type、Interfaces、Classes、Enum、Advanced Types 這幾部分說得非常清楚。
不過仍然有一種類型相關(guān)的特性不得不提——泛型。如果只是說數(shù)據(jù)類型,純粹的 JSer 們還可以理解,畢竟類型不是新鮮玩意兒,只是擴展了點種類。但是泛型這個東西,純粹的 JSer 們可能就沒啥概念了。
泛型主要是用一個符號來表示一些類型,只要是符合約束條件(默認無約束)的類型,都可以替換掉這個類型符號來使用,比如
function test(v: T) { console.log(v); } test (true); // 顯式指定 T 由 boolean 替代 test("hello"); // 推斷(隱式) T 被 string 替代 test(123); // 推斷(隱式) T 被 number 替代
泛型與強類型相關(guān),即需要進行嚴格的類型檢查,又想少寫相似代碼,所以干脆用某個符號來代替類型。泛型這個名稱本身可能并不是很好理解,但是如果借用 C++ 的“模板”概念,就好理解了。比如上面的泛型函數(shù),根據(jù)后面的調(diào)用,可以被解釋為三個函數(shù),相當(dāng)于套用模板,用實際類型代替了 T:
function test(v: boolean) { ... } function test(v: string) { ... } function test(v: number) { ... }
關(guān)于泛型,更詳細的內(nèi)容可以參考 Handbook 的 Generic 部分。
類型就簡述到這里,簡單的類型一看就能明白,高級一點的類型我們以后再開專題來詳述。不過既然選擇使用 TypeScript,必然會用到它的靜態(tài)類型特性,那就必須強化識別類型的意識,并養(yǎng)成這樣的習(xí)慣。對于純 JSer 來說,這是一個巨大的挑戰(zhàn)。
聲明類型聲明類型,主要是指聲明變量/常量,函數(shù)/方法和類成員的類型。JS 中使用 var 聲明一個變量,ES6 擴展了 let 和 const。這幾種聲明 TypeScript 都支持。要為變量或者常量指定類型也很簡單,就是在變量/常量名后面加個冒號,再指定類型即可,比如
// # typescript // 聲明函數(shù) pow 是 number 類型,即返回值是 number 類型 // 聲明參數(shù) n 是 number 類型 function pow(n: number): number { return n * n; } // 聲明 test 是無返回值的 function test(): void { for (let i: number = 0; i < 10; i++) { // 聲明 i 是 number console.log(pow(i)); } }
這段代碼演示了對函數(shù)類型、參數(shù)類型和變量類型地聲明。這相對于 JavaScript 代碼來說,似乎變得更復(fù)雜了。但是考慮下,如果我們在某處不小心這樣調(diào)用了 pow:
// # javascript let n = "a"; let r = pow(n); // 這里存在一個潛在的錯誤
JavaScript 不會提前檢查錯誤的,只有在執(zhí)行到 r = pow(n) 的時候給 r 賦值為 NaN。然后如果別處又用到 r,可能就會造成連鎖錯誤,可能很要調(diào)試一陣才把問題找得出來。
不過上面兩行代碼在 TypeScript 里是通不過轉(zhuǎn)譯的,它會報告一個類型不匹配的錯誤:
Argument of type "string" is not assignable to parameter of type "number".聲明類成員
這時先來看一段 JavaScript 代碼
// # javascript (es6) class Person { constructor(name) { this._name = name; } get name() { return this._name; } }
這段 JavaScript 代碼如果翻譯成 TypeScript 代碼,會是這樣
// # typescript class Person { private _name: string; public constructor(name: string) { this._name = name; } public get name(): string { return this._name; } }
注意到 private _name: string,這句話是在聲明類成員變量 _name。JavaScript 里是不需要聲明的,對 this._name 賦值,它自然就有了,但在 TypeScript 里如果不聲明,就會報告屬性不存在的錯誤:
Property "_name" does not exist on type "Person".
雖然寫起來麻煩了一點,但是我也能理解 TypeScript 的苦衷。如果沒有這些聲明,tsc 就搞不清楚你在使用 obj.xxxx 或者 this.xxxx 的時候,這個 xxxx 到底確實是你想要添加的屬性名稱呢,還是你不小心寫錯了的呢?
另外要注意到的是 private 和 public 修飾符。JavaScript 中存在私有成員,為了實現(xiàn)私有,大家都想了不少辦法,比如閉包。
TypeScript 提供了 private 來修飾私有成員,protected 修改保護(子類可用)成員,public 修飾公共成員。如果不添加修飾符,默認作為 public,以兼容 JavaScript 的類成員定義。不過特別需要注意的是,這些修飾符只在 TypeScript 環(huán)境(比如轉(zhuǎn)譯過程)有效,轉(zhuǎn)譯成 JavaScript 之后,仍然所有成員都是公共訪問權(quán)限的。比如上例中的 TypeScript 代碼轉(zhuǎn)譯出來基本上就是之前的 JavaScript 代碼,其 _name 屬性在外部仍可訪問。
當(dāng)然在 TypeScript 代碼中,如果外部訪問了 _name,tsc 是會報告錯誤的
Property "_name" is private and only accessible within class "Person".
所以應(yīng)用內(nèi)使用 private 完全沒問題,但是如果你寫的東西需要做為第三方庫發(fā)布,那就要想一些手段來進行“私有化”了,其手段和 JavaScript 并沒什么不同。
小結(jié)從 JavaScript 語法改寫 TypeScript 語法,我們來做個簡單的總結(jié):
類成員需要聲明。
變量、函數(shù)參數(shù)和返回值需要申明類型。
如果所有這些東西都要聲明類型,工作量還是滿大的,所以我建議:就接口部分聲明類型。也就是說,類成員、函數(shù)/方法的參數(shù)和返回類型要聲明類型,便于編輯器進行語法提示,局部使用的變量或者箭頭函數(shù),在能明確推導(dǎo)出其類型的時候,可以不聲明類型。
擴展閱讀從 JavaScript 到 TypeScript - 模塊化和構(gòu)建
從 JavaScript 到 TypeScript - 泛型
從 JavaScript 到 TypeScript - 接口
關(guān)注作者的公眾號“邊城客棧” →
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/83326.html
摘要:前面講泛型的時候,提到了接口。和泛型一樣,接口也是目前中并不存在的語法。不過可不吃這一套,所以這里通過注釋關(guān)閉了對該接口的命名檢查。這樣的接口不能由類實現(xiàn)。 前面講 泛型 的時候,提到了接口。和泛型一樣,接口也是目前 JavaScript 中并不存在的語法。 由于泛型語法總是附加在類或函數(shù)語法中,所以從 TypeScript 轉(zhuǎn)譯成 JavaScript 之后,至少還存在類和函數(shù)(只是...
摘要:能夠根據(jù)返回語句自動推斷出返回值類型,因此我們通常省略它。定義的函數(shù)類型接口就像是一個只有參數(shù)列表和返回值類型的函數(shù)定義??伤饕愋途哂幸粋€索引簽名,它描述了對象索引的類型,還有相應(yīng)的索引返回值類型。 showImg(https://segmentfault.com/img/remote/1460000010018621?w=640&h=280); 本文首發(fā)在我的個人博客:http:/...
摘要:遷移至指南為什么要遷移至本身是動態(tài)弱類型的語言,這樣的特點導(dǎo)致了代碼中充斥著很多的報錯,給開發(fā)調(diào)試和線上代碼穩(wěn)定都帶來了不小的負面影響??尚行砸驗槭堑某?,不會阻止的運行,即使存在類型錯誤也不例外,這能讓你的逐步遷移至。 Vue2.5+遷移至Typescript指南 為什么要遷移至Typescript Javascript本身是動態(tài)弱類型的語言,這樣的特點導(dǎo)致了Javascript代碼...
摘要:遷移至指南為什么要遷移至本身是動態(tài)弱類型的語言,這樣的特點導(dǎo)致了代碼中充斥著很多的報錯,給開發(fā)調(diào)試和線上代碼穩(wěn)定都帶來了不小的負面影響??尚行砸驗槭堑某粫柚沟倪\行,即使存在類型錯誤也不例外,這能讓你的逐步遷移至。 Vue2.5+遷移至Typescript指南 為什么要遷移至Typescript Javascript本身是動態(tài)弱類型的語言,這樣的特點導(dǎo)致了Javascript代...
閱讀 2570·2021-11-23 09:51
閱讀 3365·2021-11-22 15:22
閱讀 1878·2021-11-18 13:22
閱讀 2272·2021-09-24 09:48
閱讀 1318·2019-08-29 13:58
閱讀 1309·2019-08-26 13:39
閱讀 2452·2019-08-26 10:48
閱讀 3040·2019-08-26 10:21