国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

精讀《Typescript2.0 - 2.9》

william / 1196人閱讀

摘要:比如或者都會導(dǎo)致函數(shù)返回值類型時。和特性一樣,等于是函數(shù)返回值中的或。注意對比下面的寫法對于,它的返回值是可迭代的對象,并且每個類型都是或者。首先是不支持方法重載的,是支持的,而類型系統(tǒng)一定程度在對標(biāo),當(dāng)然要支持這個功能。

1 引言

精讀原文是 typescript 2.0-2.9 的文檔:

2.0-2.8,2.9 草案.

我發(fā)現(xiàn),許多寫了一年以上 Typescript 開發(fā)者,對 Typescript 對理解和使用水平都停留在入門階段。造成這個現(xiàn)象的原因是,Typescript 知識的積累需要 刻意練習(xí),使用 Typescript 的時間與對它的了解程度幾乎沒有關(guān)系。

這篇文章精選了 TS 在 2.0-2.9 版本中最重要的功能,并配合實(shí)際案例解讀,幫助你快速跟上 TS 的更新節(jié)奏。

對于 TS 內(nèi)部優(yōu)化的用戶無感部分并不會羅列出來,因?yàn)檫@些優(yōu)化都可在日常使用過程中感受到。

2 精讀

由于 Typescript 在嚴(yán)格模式下的許多表現(xiàn)都與非嚴(yán)格模式不同,為了避免不必要的記憶,建議只記嚴(yán)格模式就好了!

嚴(yán)格模式導(dǎo)致的大量邊界檢測代碼,已經(jīng)有解了

直接訪問一個變量的屬性時,如果這個變量是 undefined,不但屬性訪問不到,js 還會拋出異常,這幾乎是業(yè)務(wù)開發(fā)中最高頻的報錯了(往往是后端數(shù)據(jù)異常導(dǎo)致的),而 typescript 的 strict 模式會檢查這種情況,不允許不安全的代碼出現(xiàn)。

2.0 版本,提供了 “非空斷言標(biāo)志符” !. 解決明確不會報錯的情況,比如配置文件是靜態(tài)的,那肯定不會拋出異常,但在 2.0 之前的版本,我們可能要這么調(diào)用對象:

const config = {
  port: 8000
};

if (config) {
  console.log(config.port);
}

有了 2.0 提供的 “非空斷言標(biāo)志符”,我們可以這么寫了:

console.log(config!.port);

2.8 版本,ts 支持了條件類型語法:

type TypeName = T extends string ? "string"

當(dāng) T 的類型是 string 時,TypeName 的表達(dá)式類型為 "string"。

這這時可以構(gòu)造一個自動 “非空斷言” 的類型,把代碼簡化為:

console.log(config.port);

前提是框架先把 config 指定為這個特殊類型,這個特殊類型的定義如下:

export type PowerPartial = {
  [U in keyof T]?: T[U] extends object ? PowerPartial : T[U]
};

也就是 2.8 的條件類型允許我們在類型判斷進(jìn)行遞歸,把所有對象的 key 都包一層 “非空斷言”!

此處靈感來自 egg-ts 總結(jié)
增加了 never object 類型

當(dāng)一個函數(shù)無法執(zhí)行完,或者理解為中途中斷時,TS 2.0 認(rèn)為它是 never 類型。

比如 throw Error 或者 while(true) 都會導(dǎo)致函數(shù)返回值類型時 never

null undefined 特性一樣,never 等于是函數(shù)返回值中的 nullundefined它們都是子類型,比如類型 number 自帶了 nullundefined 這兩個子類型,是因?yàn)槿魏斡蓄愋偷闹刀加锌赡苁强眨ㄒ簿褪菆?zhí)行期間可能沒有值)。

這里涉及到很重要的概念,就是預(yù)定義了類型不代表類型一定如預(yù)期,就好比函數(shù)運(yùn)行時可能因?yàn)?throw Error 而中斷。所以 ts 為了處理這種情況,null undefined 設(shè)定為了所有類型的子類型,而從 2.0 開始,函數(shù)的返回值類型又多了一種子類型 never

TS 2.2 支持了 object 類型, 但許多時候我們總把 objectany 類型弄混淆,比如下面的代碼:

const persion: object = {
  age: 5
};
console.log(persion.age); // Error: Property "age" does not exist on type "object".

這時候報錯會出現(xiàn),有時候閉個眼改成 any 就完事了。其實(shí)這時候只要把 object 刪掉,換成 TS 的自動推導(dǎo)就搞定了。那么問題出在哪里?

首先 object 不是這么用的,它是 TS 2.3 版本中加入的,用來描述一種非基礎(chǔ)類型,所以一般用在類型校驗(yàn)上,比如作為參數(shù)類型。如果參數(shù)類型是 object,那么允許任何對象數(shù)據(jù)傳入,但不允許 3 "abc" 這種非對象類型:

declare function create(o: object | null): void;

create({ prop: 0 }); // 正確
create(null); // 正確

create(42); // 錯誤
create("string"); // 錯誤
create(false); // 錯誤
create(undefined); // 錯誤

而一開始 const persion: object 這種用法,是將能精確推導(dǎo)的對象類型,擴(kuò)大到了整體的,模糊的對象類型,TS 自然無法推斷這個對象擁有哪些 key,因?yàn)閷ο箢愋蛢H表示它是一個對象類型,在將對象作為整體觀察時是成立的,但是 object 類型是不承認(rèn)任何具體的 key 的。

增加了修飾類型

TS 在 2.0 版本支持了 readonly 修飾符,被它修飾的變量無法被修改。

在 TS 2.8 版本,又增加了 -+ 修飾修飾符,有點(diǎn)像副詞作用于形容詞。舉個例子,readonly 就是 +readonly,我們也可以使用 -readonly 移除只讀的特性;也可以通過 -?: 的方式移除可選類型,因此可以延伸出一種新類型:Required,將對象所有可選修飾移除,自然就成為了必選類型:

type Required = { [P in keyof T]-?: T[P] };
可以定義函數(shù)的 this 類型

也是 TS 2.0 版本中,我們可以定制 this 的類型,這個在 vue 框架中尤為有用:

function f(this: void) {
  // make sure `this` is unusable in this standalone function
}

this 類型是一種假參數(shù),所以并不會影響函數(shù)真正參數(shù)數(shù)量與位置,只不過它定義在參數(shù)位置上,而且永遠(yuǎn)會插隊(duì)在第一個。

引用、尋址支持通配符了

簡單來說,就是模塊名可以用 * 表示任何單詞了:

declare module "*!text" {
  const content: string;
  export default content;
}

它的類型可以輻射到:

import fileContent from "./xyz.txt!text";

這個特性很強(qiáng)大的一個點(diǎn)是用在拓展模塊上,因?yàn)榘?tsconfig.json 的模塊查找也支持通配符了!舉個例子一下就懂:

最近比較火的 umi 框架,它有一個 locale 插件,只要安裝了這個插件,就可以從 umi/locale 獲取國際化內(nèi)容:

import { locale } from "umi/locale";

其實(shí)它的實(shí)現(xiàn)是創(chuàng)建了一個文件,通過 webpack.alias 將引用指了過去。這個做法非常棒,那么如何為它加上類型支持呢?只要這么配置 tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "umi/*": ["umi", ""]
    }
  }
}

將所有 umi/* 的類型都指向 ,那么 umi/locale 就會指向 /locale.ts 這個文件,如果插件自動創(chuàng)建的文件名也恰好叫 locale.ts,那么類型就自動對應(yīng)上了。

跳過倉庫類型報錯

TS 在 2.x 支持了許多新 compileOptions,但 skipLibCheck 實(shí)在是太耀眼了,筆者必須多帶帶提出來說。

skipLibCheck 這個屬性不但可以忽略 npm 不規(guī)范帶來的報錯,還能最大限度的支持類型系統(tǒng),可謂一舉兩得。

拿某 UI 庫舉例,某天發(fā)布的小版本 d.ts 文件出現(xiàn)一個漏洞,導(dǎo)致整個項(xiàng)目構(gòu)建失敗,你不再需要提 PR 催促作者修復(fù)了!skipLibCheck 可以忽略這種報錯,同時還能保持類型的自動推導(dǎo),也就是說這比 declare module "ui-lib" 將類型設(shè)置為 any 更強(qiáng)大。

對類型修飾的增強(qiáng)

TS 2.1 版本可謂是針對類型操作革命性的版本,我們可以通過 keyof 拿到對象 key 的類型:

interface Person {
  name: string;
  age: number;
}

type K1 = keyof Person; // "name" | "age"

基于 keyof,我們可以增強(qiáng)對象的類型:

type NewObjType = { [P in keyof T]: T[P] };

Tips:在 TS 2.8 版本,我們可以以表達(dá)式作為 keyof 的參數(shù),比如 keyof (A & B)
Tips:在 TS 2.9 版本,keyof 可能返回非 string 類型的值,因此從一開始就不要認(rèn)為 keyof 的返回類型一定是 string

NewObjType 原封不動的將對象類型重新描述了一遍,這看上去沒什么意義。但實(shí)際上我們有三處拓展的地方:

左邊:比如可以通過 readonly 修飾,將對象的屬性變成只讀。

中間:比如將 : 改成 ?:,將對象所有屬性變成可選。

右邊:比如套一層 Promise,將對象每個 keyvalue 類型覆蓋。

基于這些能力,我們拓展出一系列上層很有用的 interface

Readonly。把對象 key 全部設(shè)置為只讀,或者利用 2.8 的條件類型語法,實(shí)現(xiàn)遞歸設(shè)置只讀。

Partial。把對象的 key 都設(shè)置為可選。

Pick。從對象類型 T 挑選一些屬性 K,比如對象擁有 10 個 key,只需要將 K 設(shè)置為 "name" | "age" 就可以生成僅支持這兩個 key 的新對象類型。

Extract。是 Pick 的底層 API,直到 2.8 版本才內(nèi)置進(jìn)來,可以認(rèn)為 Pick 是挑選對象的某些 key,Extract 是挑選 key 中的 key。

Record。將對象某些屬性轉(zhuǎn)換成另一個類型。比較常見用在回調(diào)場景,回調(diào)函數(shù)返回的類型會覆蓋對象每一個 key 的類型,此時類型系統(tǒng)需要 Record 接口才能完成推導(dǎo)。

Exclude。將 T 中的 U 類型排除,和 Extract 功能相反。

Omit(未內(nèi)置)。從對象 T 中排除 key 是 K 的屬性。可以利用內(nèi)置類型方便推導(dǎo)出來:type Omit = Pick>

NonNullable。排除 Tnullundefined 的可能性。

ReturnType。獲取函數(shù) T 返回值的類型,這個類型意義很大。

InstanceType。獲取一個構(gòu)造函數(shù)類型的實(shí)例類型。

以上類型都內(nèi)置在 lib.d.ts 中,不需要定義就可直接使用,可以認(rèn)為是 Typescript 的 utils 工具庫。

多帶帶拿 ReturnType 舉個例子,體現(xiàn)出其重要性:

Redux 的 Connect 第一個參數(shù)是 mapStateToProps,這些 Props 會自動與 React Props 聚合,我們可以利用 ReturnType 拿到當(dāng)前 Connect 注入給 Props 的類型,就可以打通 Connect 與 React 組件的類型系統(tǒng)了。

對 Generators 和 async/await 的類型定義

TS 2.3 版本做了許多對 Generators 的增強(qiáng),但實(shí)際上我們早已用 async/await 替代了它,所以 TS 對 Generators 的增強(qiáng)可以忽略。需要注意的一塊是對 for..of 語法的異步迭代支持:

async function f() {
  for await (const x of fn1()) {
    console.log(x);
  }
}

這可以對每一步進(jìn)行異步迭代。注意對比下面的寫法:

async function f() {
  for (const x of await fn2()) {
    console.log(x);
  }
}

對于 fn1,它的返回值是可迭代的對象,并且每個 item 類型都是 Promise 或者 Generator。對于 fn2,它自身是個異步函數(shù),返回值是可迭代的,而且每個 item 都不是異步的。舉個例子:

function fn1() {
  return [Promise.resolve(1), Promise.resolve(2)];
}

function fn2() {
  return [1, 2];
}

在這里順帶一提,對 Array.map 的每一項(xiàng)進(jìn)行異步等待的方法:

await Promise.all(
  arr.map(async item => {
    return await item.run();
  })
);

如果為了執(zhí)行順序,可以換成 for..of 的語法,因?yàn)閿?shù)組類型是一種可迭代類型。

泛型默認(rèn)參數(shù)

了解這個之前,先介紹一下 TS 2.0 之前就支持的函數(shù)類型重載。

首先 JS 是不支持方法重載的,Java 是支持的,而 TS 類型系統(tǒng)一定程度在對標(biāo) Java,當(dāng)然要支持這個功能。好在 JS 有一些偏方實(shí)現(xiàn)偽方法重載,典型的是 redux 的 createStore

export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === "function" && typeof enhancer === "undefined") {
    enhancer = preloadedState;
    preloadedState = undefined;
  }
}

既然 JS 有辦法支持方法重載,那 TS 補(bǔ)充了函數(shù)類型重載,兩者結(jié)合就等于 Java 方法重載:

declare function createStore(
  reducer: Reducer,
  preloadedState: PreloadedState,
  enhancer: Enhancer
);
declare function createStore(reducer: Reducer, enhancer: Enhancer);

可以清晰的看到,createStore 想表現(xiàn)的是對參數(shù)個數(shù)的重載,如果定義了函數(shù)類型重載,TS 會根據(jù)函數(shù)類型自動判斷對應(yīng)的是哪個定義。

而在 TS 2.3 版本支持了泛型默認(rèn)參數(shù),可以某些場景減少函數(shù)類型重載的代碼量,比如對于下面的代碼:

declare function create(): Container;
declare function create(element: T): Container;
declare function create(
  element: T,
  children: U[]
): Container;

通過枚舉表達(dá)了范型默認(rèn)值,以及 U 與 T 之間可能存在的關(guān)系,這些都可以用泛型默認(rèn)參數(shù)解決:

declare function create(
  element?: T,
  children?: U
): Container;

尤其在 React 使用過程中,如果用泛型默認(rèn)值定義了 Component

.. Component ..

就可以實(shí)現(xiàn)以下等價的效果:

class Component extends React.PureComponent {
  //...
}
// 等價于
class Component extends React.PureComponent {
  //...
}
動態(tài) Import

TS 從 2.4 版本開始支持了動態(tài) Import,同時 Webpack4.0 也支持了這個語法(在 精讀《webpack4.0%20 升級指南》 有詳細(xì)介紹),這個語法就正式可以用于生產(chǎn)環(huán)境了:

const zipUtil = await import("./utils/create-zip-file");
準(zhǔn)確的說,動態(tài) Import 實(shí)現(xiàn)于 webpack 2.1.0-beta.28,最終在 TS 2.4 版本獲得了語法支持。

在 TS 2.9 版本開始,支持了 import() 類型定義:

const zipUtil: typeof import("./utils/create-zip-file") = await import("./utils/create-zip-file")

也就是 typeof 可以作用于 import() 語法,而不真正引入 js 內(nèi)容。不過要注意的是,這個 import("./utils/create-zip-file") 路徑需要可被推導(dǎo),比如要存在這個 npm 模塊、相對路徑、或者在 tsconfig.json 定義了 paths

好在 import 語法本身限制了路徑必須是字面量,使得自動推導(dǎo)的成功率非常高,只要是正確的代碼幾乎一定可以推導(dǎo)出來。好吧,所以這也從另一個角度推薦大家放棄 require

Enum 類型支持字符串

從 Typescript 2.4 開始,支持了枚舉類型使用字符串做為 value:

enum Colors {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

筆者在這提醒一句,這個功能在純前端代碼內(nèi)可能沒有用。因?yàn)樵?TS 中所有 enum 的地方都建議使用 enum 接收,下面給出例子:

// 正確
{
  type: monaco.languages.types.Folder;
}
// 錯誤
{
  type: 75;
}

不僅是可讀性,enum 對應(yīng)的數(shù)字可能會改變,直接寫 75 的做法存在風(fēng)險。

但如果前后端存在交互,前端是不可能發(fā)送 enum 對象的,必須要轉(zhuǎn)化成數(shù)字,這時使用字符串作為 value 會更安全:

enum types {
  Folder = "FOLDER"
}

fetch(`/api?type=${monaco.languages.types.Folder}`);
數(shù)組類型可以明確長度

最典型的是 chart 圖,經(jīng)常是這樣的二維數(shù)組數(shù)據(jù)類型:

[[1, 5.5], [2, 3.7], [3, 2.0], [4, 5.9], [5, 3.9]]

一般我們會這么描述其數(shù)據(jù)結(jié)構(gòu):

const data: string[][] = [[1, 5.5], [2, 3.7], [3, 2.0], [4, 5.9], [5, 3.9]];

在 TS 2.7 版本中,我們可以更精確的描述每一項(xiàng)的類型與數(shù)組總長度:

interface ChartData extends Array {
  0: number;
  1: number;
  length: 2;
}
自動類型推導(dǎo)

自動類型推導(dǎo)有兩種,分別是 typeof:

function foo(x: string | number) {
  if (typeof x === "string") {
    return x; // string
  }
  return x; // number
}

instanceof:

function f1(x: B | C | D) {
  if (x instanceof B) {
    x; // B
  } else if (x instanceof C) {
    x; // C
  } else {
    x; // D
  }
}

在 TS 2.7 版本中,新增了 in 的推導(dǎo):

interface A {
  a: number;
}
interface B {
  b: string;
}

function foo(x: A | B) {
  if ("a" in x) {
    return x.a;
  }
  return x.b;
}

這個解決了 object 類型的自動推導(dǎo)問題,因?yàn)?object 既無法用 keyof 也無法用 instanceof 判定類型,因此找到對象的特征吧,再也不要用 as 了:

// Bad
function foo(x: A | B) {
  // I know it"s A, but i can"t describe it.
  (x as A).keyofA;
}

// Good
function foo(x: A | B) {
  // I know it"s A, because it has property `keyofA`
  if ("keyofA" in x) {
    x.keyofA;
  }
}
4 總結(jié)

Typescript 2.0-2.9 文檔整體讀下來,可以看出還是有較強(qiáng)連貫性的。但我們可能并不習(xí)慣一步步學(xué)習(xí)新語法,因?yàn)樾抡Z法需要時間消化、同時要連接到以往語法的上下文才能更好理解,所以本文從功能角度,而非版本角度梳理了 TS 的新特性,比較符合學(xué)習(xí)習(xí)慣。

另一個感悟是,我們也許要用追月刊漫畫的思維去學(xué)習(xí)新語言,特別是 TS 這種正在發(fā)展中,并且迭代速度很快的語言。

5 更多討論
討論地址是:精讀《Typescript2.0 - 2.9》 · Issue #85 · dt-fe/weekly

如果你想?yún)⑴c討論,請點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95308.html

相關(guān)文章

  • 精讀《Typescript 3.2 新特性》

    摘要:引言發(fā)布了幾個新特性,主要變化是類型檢查更嚴(yán)格,對一些時髦功能拓展了類型支持。精讀這次改動意圖非常明顯,是為了跟上的新語法。基本可以算是對社區(qū)的回饋。討論地址是精讀新特性如果你想?yún)⑴c討論,請點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1 引言 Typescript 3.2 發(fā)布了幾個新特性,主要變化是類型檢查更嚴(yán)格,對 ES6、ES7 一些時髦功能拓展了類型支持。 2 概要 下面挑一...

    cucumber 評論0 收藏0
  • 前端進(jìn)階資源整理

    摘要:前端進(jìn)階進(jìn)階構(gòu)建項(xiàng)目一配置最佳實(shí)踐狀態(tài)管理之痛點(diǎn)分析與改良開發(fā)中所謂狀態(tài)淺析從時間旅行的烏托邦,看狀態(tài)管理的設(shè)計(jì)誤區(qū)使用更好地處理數(shù)據(jù)愛彼迎房源詳情頁中的性能優(yōu)化從零開始,在中構(gòu)建時間旅行式調(diào)試用輕松管理復(fù)雜狀態(tài)如何把業(yè)務(wù)邏輯這個故事講好和 前端進(jìn)階 webpack webpack進(jìn)階構(gòu)建項(xiàng)目(一) Webpack 4 配置最佳實(shí)踐 react Redux狀態(tài)管理之痛點(diǎn)、分析與...

    BlackMass 評論0 收藏0
  • 精讀《源碼學(xué)習(xí)》

    摘要:精讀原文介紹了學(xué)習(xí)源碼的兩個技巧,并利用實(shí)例說明了源碼學(xué)習(xí)過程中可以學(xué)到許多周邊知識,都讓我們受益匪淺。討論地址是精讀源碼學(xué)習(xí)如果你想?yún)⑴c討論,請點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1. 引言 javascript-knowledge-reading-source-code 這篇文章介紹了閱讀源碼的重要性,精讀系列也已有八期源碼系列文章,分別是: 精讀《Immer.js》源...

    aboutU 評論0 收藏0
  • 精讀《React 的多態(tài)性》

    摘要:引言本周精讀的文章是,看看作者是如何解釋這個多態(tài)性含義的。讀完文章才發(fā)現(xiàn),文章標(biāo)題改為的多態(tài)性更妥當(dāng),因?yàn)檎恼露荚谡f,而使用場景不局限于。更多討論討論地址是精讀的多態(tài)性如果你想?yún)⑴c討論,請點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1 引言 本周精讀的文章是:surprising-polymorphism-in-react-applications,看看作者是如何解釋這個多態(tài)性含...

    tabalt 評論0 收藏0
  • 精讀《用 Reduce 實(shí)現(xiàn) Promise 串行執(zhí)行》

    摘要:引言本周精讀的文章是,講了如何利用實(shí)現(xiàn)串行執(zhí)行。總結(jié)串行隊(duì)列一般情況下用的不多,因?yàn)榇袝枞脩艚换ネ遣⑿械摹8嘤懻撚懻摰刂肥蔷x用實(shí)現(xiàn)串行執(zhí)行如果你想?yún)⑴c討論,請點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1 引言 本周精讀的文章是 why-using-reduce-to-sequentially-resolve-promises-works,講了如何利用 reduce...

    JinB 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<