TypeScript 2.5~2.6 新特性一覽
TypeScript 團隊周二發布了 TypeScript 2.6, 帶來了包括嚴格函數類型和更快的 tsc --watch 在內的多個新特性. 再早一些的 TypeScript 2.5 也帶來了包括包去重和保留符號鏈接在內的更新. (一定是) 因為 2.5 更新內容較少, 這次隨 2.6 更新一起進行了翻譯.
這次更新中 "嚴格函數類型" 的部分可能較為晦澀, TypeScript 團隊在 Announcing TypeScript 2.6 一文中做了更多解釋, 可以參考閱讀. 本文譯自 Whats new in TypeScript.
TypeScript 2.6
嚴格函數類型
TypeScript 2.6 引入了新的類型檢查選項, --strictFunctionTypes
. --strictFunctionTypes
選項是 --strict
系列選項之一, 也就是說 --strict
模式下它默認是啟用的. 你可以通過在命令行或 tsconfig.json 中設置 --strictFunctionTypes false
來單獨禁用它.
--strictFunctionTypes
啟用時, 函數類型參數的檢查是逆變(contravariantly)而非雙變(bivariantly)的. 關於變型 (variance) 對與函數類型意義的相關背景, 請查看協變(covariance)和逆變(contravariance)是什麼?.
這一更嚴格的檢查應用於除方法或構造函數聲明以外的所有函數類型. 方法被專門排除在外是為了確保帶泛型的類和介面(如 Array<T>
)總體上仍然保持協變.
考慮下面這個 Animal
是 Dog
和 Cat
的父類型的例子:
declare let f1: (x: Animal) => void;ndeclare let f2: (x: Dog) => void;ndeclare let f3: (x: Cat) => void;nf1 = f2; // 啟用 --strictFunctionTypes 時錯誤nf2 = f1; // 正確nf2 = f3; // 錯誤 n
第一個賦值語句在默認的類型檢查模式中是允許的, 但是在嚴格函數類型模式下會被標記錯誤. 通俗地講, 默認模式允許這麼賦值, 因為它可能是合理的, 而嚴格函數類型模式將它標記為錯誤, 因為它不能被證明合理. 任何一種模式中, 第三個賦值都是錯誤的, 因為它永遠不合理.
用另一種方式來描述這個例子則是, 默認類型檢查模式中 T
在類型 (x: T) => void
是雙變的 (也即協變或逆變), 但在嚴格函數類型模式中 T
是逆變的.
例子
interface Comparer<T> {n compare: (a: T, b: T) => number;n}nndeclare let animalComparer: Comparer<Animal>;ndeclare let dogComparer: Comparer<Dog>;nnanimalComparer = dogComparer; // 錯誤ndogComparer = animalComparer; // 正確 n
現在第一個賦值是錯誤的. 更明確地說, Comparer<T>
中的 T
因為僅在函數類型參數的位置被使用, 是逆變的.
另外, 注意儘管有的語言 (比如 C# 和 Scala) 要求變型標註 (variance annotations) (out
/in
或 +
/-
), 而由於 TypeScript 的結構化類型系統, 它的變型是由泛型中的類型參數的實際使用自然得出的.
注意
啟用 --strictFunctionTypes
時, 如果 compare
被聲明為方法, 則第一個賦值依然是被允許的. 更明確的說, Comparer<T>
中的 T
因為僅在方法參數的位置被使用所以是雙變的.
interface Comparer<T> {n compare(a: T, b: T): number;n}nndeclare let animalComparer: Comparer<Animal>;ndeclare let dogComparer: Comparer<Dog>;nnanimalComparer = dogComparer; // 正確, 因為雙變ndogComparer = animalComparer; // 正確 n
TypeScript 2.6 還改進了與逆變位置相關的類型推導:
function combine<T>(...funcs: ((x: T) => void)[]): (x: T) => void {n return x => {n for (const f of funcs) f(x);n }n}nnfunction animalFunc(x: Animal) {}nfunction dogFunc(x: Dog) {}nnlet combined = combine(animalFunc, dogFunc); // (x: Dog) => void n
這上面所有 T
的推斷都來自逆變的位置, 由此我們得出 T
的最普遍子類型. 這與從協變位置推導出的結果恰恰相反, 從協變位置我們得出的是最普遍超類型.
緩存模塊中的標籤模板對象
TypeScript 2.6 修復了標籤字元串模板的輸出, 以更好地遵循 ECMAScript 標準. 根據 ECMAScript 標準, 每一次獲取模板標籤的值時, 應該將同一個模板字元串數組對象 (同一個 TemplateStringArray
) 作為第一個參數傳遞. 在 TypeScript 2.6 之前, 每一次生成的都是全新的模板對象. 雖然字元串的內容是一樣的, 這樣的輸出會影響通過識別字元串來實現緩存失效的庫, 比如 lit-html.
例子
export function id(x: TemplateStringsArray) {n return x;n}nnexport function templateObjectFactory() {n return id`hello world`;n}nnlet result = templateObjectFactory() === templateObjectFactory(); // TS 2.6 為 true n
編譯後的代碼:
"use strict";nvar __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {n if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }n return cooked;n};nnfunction id(x) {n return x;n}nnvar _a;nfunction templateObjectFactory() {n return id(_a || (_a = __makeTemplateObject(["hello world"], ["hello world"])));n}nnvar result = templateObjectFactory() === templateObjectFactory(); n
注意: 這一改變引入了新的工具函數,
__makeTemplateObject
; 如果你在搭配使用--importHelpers
和tslib
, 需要更新到 1.8 或更高版本.
本地化的命令行診斷消息
TypeScript 2.6 npm 包加入了 13 種語言的診斷消息本地化版本. 命令行中本地化消息會在使用 --locale
選項時顯示.
例子
俄語顯示的錯誤消息:
c:ts>tsc --vnVersion 2.6.1nnc:ts>tsc --locale ru --pretty c:testa.tsnn../test/a.ts(1,5): error TS2322: Тип ""string"" не может быть назначен для типа "number".nn1 var x: number = "string";n ~ n
中文顯示的幫助信息:
PS C:ts> tsc --vnVersion 2.6.1nnPS C:ts> tsc --locale zh-cnn版本 2.6.1n語法: tsc [選項] [文件 ...]nn示例: tsc hello.tsn tsc --outFile file.js file.tsn tsc @args.txtnn選項:n -h, --help 列印此消息。n --all 顯示所有編譯器選項。n -v, --version 列印編譯器的版本。n --init 初始化 TypeScript 項目並創建 tsconfig.json 文件。n -p 文件或目錄, --project 文件或目錄 編譯給定了其配置文件路徑或帶 "tsconfig.json" 的文件夾路徑的項目。n --pretty 使用顏色和上下文風格化錯誤和消息(實驗)。n -w, --watch 監視輸入文件。n -t 版本, --target 版本 指定 ECMAScript 目標版本: "ES3"(默認)、"ES5"、"ES2015"、"ES2016"、"ES2017" 或 "ESNEXT"。n -m 種類, --module 種類 指定模塊代碼生成: "none"、"commonjs"、"amd"、"system"、"umd"、"es2015"或 "ESNext"。n --lib 指定要在編譯中包括的庫文件:n es5 es6 es2015 es7 es2016 es2017 esnext dom dom.iterable webworker scripthost es2015.core es2015.collection es2015.generator es2015.iterable es2015.promise es2015.proxy es2015.reflect es2015.symbol es2015.symbol.wellknown es2016.array.include es2017.object es2017.sharedmemory es2017.string es2017.intl esnext.asynciterablen --allowJs 允許編譯 JavaScript 文件。n --jsx 種類 指定 JSX 代碼生成: "preserve"、"react-native" 或 "react"。 -d, --declaration 生成相應的 ".d.ts" 文件。n --sourceMap 生成相應的 ".map" 文件。n --outFile 文件 連接輸出並將其發出到單個文件。n --outDir 目錄 將輸出結構重定向到目錄。n --removeComments 請勿將注釋發出到輸出。n --noEmit 請勿發出輸出。n --strict 啟用所有嚴格類型檢查選項。n --noImplicitAny 對具有隱式 "any" 類型的表達式和聲明引發錯誤。n --strictNullChecks 啟用嚴格的 NULL 檢查。n --strictFunctionTypes 對函數類型啟用嚴格檢查。n --noImplicitThis 在帶隱式「any" 類型的 "this" 表達式上引發錯誤。n --alwaysStrict 以嚴格模式進行分析,並為每個源文件發出 "use strict" 指令。n --noUnusedLocals 報告未使用的局部變數上的錯誤。n --noUnusedParameters 報告未使用的參數上的錯誤。n --noImplicitReturns 在函數中的所有代碼路徑並非都返回值時報告錯誤。n --noFallthroughCasesInSwitch 報告 switch 語句中遇到 fallthrough 情況的錯誤。n --types 要包含在編譯中類型聲明文件。n @<文件> 從文件插入命令行選項和文件。 n
通過 // @ts-ignore 注釋隱藏 .ts 文件中的錯誤
TypeScript 2.6 支持在 .ts 文件中通過在報錯一行上方使用 // @ts-ignore
來忽略錯誤.
例子
if (false) {n // @ts-ignore: 無法被執行的代碼的錯誤n console.log("hello");n} n
// @ts-ignore
注釋會忽略下一行中產生的所有錯誤. 建議實踐中在 @ts-ignore
之後添加相關提示, 解釋忽略了什麼錯誤.
請注意, 這個注釋僅會隱藏報錯, 並且我們建議你極少使用這一注釋.
更快的 tsc --watch
TypeScript 2.6 帶來了更快的 --watch
實現. 新版本優化了使用 ES 模塊的代碼的生成和檢查. 在一個模塊文件中檢測到的改變只會使改變的模塊, 以及依賴它的文件被重新生成, 而不再是整個項目. 有大量文件的項目應該從這一改變中獲益最多.
這一新的實現也為 tsserver 中的監聽帶來了性能提升. 監聽邏輯被完全重寫以更快響應改變事件.
只寫的引用現在會被標記未使用
TypeScript 2.6 加入了修正的 --noUnusedLocals
和 --noUnusedParameters
編譯選項實現. 只被寫但從沒有被讀的聲明現在會被標記未使用.
例子
下面 n
和 m
都會被標記為未使用, 因為它們的值從未被讀取. 之前 TypeScript 只會檢查它們的值是否被引用.
function f(n: number) {n n = 0;n}nnclass C {n private m: number;n constructor() {n this.m = 0;n }n} n
另外僅被自己內部調用的函數也會被認為是未使用的.
例子
function f() {n f(); // 錯誤: f 被聲明, 但它的值從未被使用n} n
TypeScript 2.5
可選的 catch
語句變數
得益於 @tinganho 做的工作, TypeScript 2.5 實現了一個新的 ECMAScript 特性, 允許用戶省略 catch
語句中的變數. 舉例來說, 當使用 JSON.parse
時, 你可能需要將對應的函數調用放在 try
/catch
中, 但是最後可能並不會用到輸入有誤時會拋出的 SyntaxError
(語法錯誤).
let input = "...";ntry {n JSON.parse(input);n}ncatch {n // ^ 注意我們的 `catch` 語句並沒有聲明一個變數n console.log("傳入的 JSON 不合法nn" + input)n} n
checkJs
/@ts-check
模式中的類型斷言/轉換語法
TypeScript 2.5 引入了在使用純 JavaScript 的項目中斷言表達式類型的能力. 對應的語法是 /** @type {...} */
標註注釋後加上被圓括弧括起來, 類型需要被重新演算的表達式. 舉例:
var x = /** @type {SomeType} */ (AnyParenthesizedExpression); n
包去重和重定向
在 TypeScript 2.5 中使用 Node
模塊解析策略進行導入時, 編譯器現在會檢查文件是否來自 "相同" 的包. 如果一個文件所在的包的 package.json
包含了與之前讀取的包相同的 name
和 version
, 那麼 TypeScript 會將它重定向到最頂層的包. 這可以解決兩個包可能會包含相同的類聲明, 但因為包含 private
成員導致他們在結構上不兼容的問題.
這也帶來一個額外的好處, 可以通過避免從重複的包中載入 .d.ts
文件減少內存使用和編譯器及語言服務的運行時計算.
--preserveSymlinks
(保留符號鏈接) 編譯器選項
TypeScript 2.5 帶來了 preserveSymlinks
選項, 它對應了 Node.js 中 --preserve-symlinks 選項的行為. 這一選項也會帶來和 Webpack 的 resolve.symlinks
選項相反的行為 (也就是說, 將 TypeScript 的 preserveSymlinks
選項設置為 true
對應了將 Webpack 的 resolve.symlinks
選項設為 false
, 反之亦然).
在這一模式中, 對於模塊和包的引用 (比如 import
語句和 /// <reference type="..." />
指令) 都會以相對符號鏈接文件的位置被解析, 而不是相對於符號鏈接解析到的路徑. 更具體的例子, 可以參考 Node.js 網站的文檔.
相關文章
TypeScript 2.4 新特性一覽
TypeScript 2.3 新特性一覽
TypeScript 2.2 新特性一覽
TypeScript 2.1 新特性一覽
TypeScript 2.0 新特性一覽
推薦閱讀:
※2017 年 4 月:前端與設計資源集
※(譯)關於響應式的另一種思考
※2017 年了,這麼多前端框架,你會怎樣選擇?
※精讀《最佳前端面試題》及面試官技巧
TAG:TypeScript | Angular? | 前端开发 |