TypeScript 2.9+ 版本中的幾個知識點

resolveJsonModule

TypeScript 2.9 版本中添加了一個 resolveJsonModule 編譯選項,它容許咱們在 TypeScript 模塊中導入 JSON 文件。html

在 NodeJS 中,咱們一般會導入一些 .json 文件,以下所示:git

// config.json
{
    "debug": true
}
複製代碼
const config = require('./config.json');

config.debug === true // true
複製代碼

當重寫爲 TypeScript 以後,僅僅是將 require 語法改寫成 ES Module,而不作其餘修改,TypeScript 將會拋出錯誤:github

import config from './1.json'; // Error: Cannot find module './1.json'
複製代碼

這是因爲在默認狀況下,相對路徑導入模塊時,TypeScript 只識別 .ts/tsx 文件模塊。若是你使用的是 TypeScript 2.9 前的版本,你可能會用如下方式:typescript

declare module '*.json';
複製代碼

可是它也只 decalre 了一個模塊,模塊內容仍是 any,也就是沒法獲得一些代碼提示(沒法獲得有關鍵值對信息)。json

TypeScript 2.9 添加 resolveJsonModule 編譯選項,很好的解決了這個問題:數組

config.png

unknown 替代 any

使用 TypeScript 的過程當中,不免會有使用 any 的狀況,這個時候倒不如換個方式,使用 unknown 試試。安全

unknown 最先出如今此 PR 中,隨 3.0 一塊兒發佈。它被認爲是安全版的 any,與 any 不一樣的是,unknown 僅能賦值給 any、unknown 類型,以及 unknown 上不存在任何屬性與方法。微信

let a: any = 10;        // 任何類型都能賦值給 any
let u: unknown =  10;   // 與 any 同樣,任何類型都能賦值給 unknown


let s1: string = a;     // any 能賦值給任何類型
let s2: string = u;     // 不能把 unknown 賦值給除 any、unknow 之外的其餘類型

a.method();             // any 上有任意的屬性和方法
u.method();             // unknown 沒有被斷言到一個確切類型以前,不具有任何屬性和方法
複製代碼

固然,unknown 也能被斷言,或是類型縮小至一個指定的範圍:數據結構

const name: unknown = 'hello';
const str = name as string;       // unknown 斷言爲 string 類型
const oStr = str.toUpperCase();   // HELLO

function doSome(x: unknown) {
  if (typeof x === 'string') {
    // 在這個塊中,TypeScript 知道 `x` 的類型必須是 `string`
    console.log(x.subtr(1));      // Error: 'subtr' 方法並無存在於 `string` 上
    console.log(x.substr(1));     // ok
  }

  if (x instanceof Date) {
    // x 是 Datee 類型
    console.log(x.toISOString()); // ok
  }
}
複製代碼

也可使用自定義保護類型:ui

function isNumberArray(value: unknown): value is number[] {
  return (
    Array.isArray(value) &&
    value.every(element => typeof element === "number")
  );
}

const unknownValue: unknown = [15, 23, 8, 4, 42, 16];

if (isNumberArray(unknownValue)) {
  // unknownValue 類型是 number[]
  const max = Math.max(...unknownValue);
  console.log(max);
}
複製代碼

對於 unknown 的使用,官方推薦的用法是:

咱們常常須要在 TypeScript 中描述功能最少的類型。這對於那些「但願是任何類型,可是在使用以前必須執行某種類型檢查」很是有用,它強制使用者安全性的思考它返回的值。

此外,在即將發佈的 3.5 版本中,泛型參數的隱式類型由 {} 類型,變成 unknown,即,在 3.5 如下版本時,能夠:

function test<T>(params: T) {
    return params.toString(); // ok
}
複製代碼

3.5 版本以上,這將會報錯:

function test<T>(params: T) {
    return params.toString(); // ERROR: Property 'toString' does not exist on type 'T'.
}
複製代碼

你能夠這麼作來修復它:

function test<T extends {}>(params: T) {
    return params.toString(); // ok
}
複製代碼

const 斷言

當聲明一個可變變量或者屬性時,TypeScript 一般會擴展變量類型,來確保咱們在不編寫顯示類型時,能夠賦值內容:

let x = 'hello';  // x 的類型是 string

// 能夠從新賦值
x = 'world';
複製代碼

你也能夠聲明一個字面量類型,在接下來將不能被從新賦值:

let x: 'hello' = 'hello';  // x 的類型是 hello
// 或者是 x = 'hello' as 'hello'

// error,不能從新賦值
x = 'world';
複製代碼

這種方式彷佛很極端,但在某些狀況下,倒是頗有用:

interface Test {
  pos: 'left' | 'right' | 'top' | 'bottom'
}

function func() {

  // 多是通過一系列計算獲得的值
  return {
    pos: 'left'
  }
}

  // Error: TypeScript 將會把 func 推斷爲 { pos: string },而不是 { pos: 'left' }
let t: Test = func();
複製代碼

你能夠經過字面量解決這個問題:

function func() {

  // 多是通過一系列計算獲得的值
  return {
    pos: 'left' as 'left'
  }
}

  // Error: TypeScript 將會把 func 推斷爲 { pos: string },而不是 { pos: 'left' }
let t: Test = func();
複製代碼

隨着數據結構逐漸變得複雜,這種方式變得愈來愈麻煩,const 斷言的出現,正是爲了解決這樣的問題。

function func() {

  // 多是通過一系列計算獲得的值
  return {
    pos: 'left'
  } as const
}

// ok
let t: Test = func();
複製代碼

使用 const 斷言時:

  • 表達式中的字面量類型不該該被擴展(如,不該該從字面量類型 hellostring 類型)
  • 對象字面量類型屬性只讀
  • 數組字面量成爲 readonly tuples

即:

let obj = {
  x: 10,
  y: ['hello', 2'],
  z: {
    a:
      {  b: 'top' }
  }
} as const;

// obj 的類型是:
// {
//   readonly x: 10;
//   readonly y: readonly ["hello", "2"];
//   z: {
//     a: {
//       readonly b: "top";
//     };
//   };
// }

複製代碼

參考

更多文章,請關注公衆號:

微信服務號
相關文章
相關標籤/搜索