1. 程式人生 > 實用技巧 >TypeScript字面量型別擴充套件和無型別匯入

TypeScript字面量型別擴充套件和無型別匯入

擴充套件字面量型別

當使用const關鍵字宣告區域性變數並使用字面量值初始化它時,TypeScript 將推斷該變數的字面量型別:

const stringLiteral = "https"; // Type "https"
const numericLiteral = 42;     // Type 42
const booleanLiteral = true;   // Type true

由於const關鍵字,每個變數的值都不能更改,所以字面量型別非常有意義。它儲存了關於被賦值的確切資訊。

如果如果let宣告上述的變數,那麼每個字面量型別都被擴充套件為相應的擴充套件型別:

let widenedStringLiteral = stringLiteral;   // Type string
let widenedNumericLiteral = numericLiteral; // Type number
let widenedBooleanLiteral = booleanLiteral; // Type boolean

與const變數相反,使用let宣告的變數是可以修改的。如果 TypeScript 為let變數推斷一個字面量型別,那麼嘗試為指定的值以外的任何值賦值都會在編譯時產生錯誤。

因此,對於上述每個let變數,都會推斷出擴充套件的型別,列舉字面量也是如此:

enum FlexDirection {
  Row,
  Column
}

const enumLiteral = FlexDirection.Row; //  FlexDirection.Row 型別
let widenedEnumLiteral = enumLiteral; // FlexDirection 型別

總結一下,下面是擴大字面量型別的規則:

  • 字串字面量型別被擴充套件為string型別
  • 數字字面量型別被擴充套件為number型別
  • 布林字面量型別被擴充套件為boolean型別
  • 列舉字面量型別被擴充套件為包含列舉的型別

到目前為止,咱們一直在研究字面量型別的擴充套件,在必要時自動擴充套件。現在來看看非擴充套件字面量型別,如名所示,它們不會自動地擴充套件。

非擴充套件字面量型別

可以通過顯式地將變數標註為字面量型別來建立非擴充套件字面量型別的變數

const stringLiteral: "https" = "https"; // 型別 "https" (非擴充套件)
const numericLiteral: 42 = 42; // 型別 42 (非擴充套件)

將非擴充套件字面量型別的變數的值賦給另一個變數,該變數將不會擴充套件。

let widenedStringLiteral = stringLiteral; // 型別 "https" (非擴充套件)
let widenedNumericLiteral = numericLiteral; // 型別 42 (非擴充套件)

非擴充套件字面量型別的好處

為了理解非擴充套件字面量型別的是有用的,咱們再來看看擴充套件字面量型別。在下面的例子中,一個數組是由兩個可擴充套件字串字面量型別的變數建立的:

const http = "http"; // Type "http" (可擴充套件)
const https = "https"; // Type "https" (可擴充套件)

const protocols = [http, https]; // Type string[]

const first = protocols[0]; // Type string
const second = protocols[1]; // Type string

TypeScript 推斷陣列protocols的型別為string[]。因此,像first和second這樣的陣列元素型別被擴充套件為string。字面量型別"http"和"https"的概念在擴充套件過程中丟失了。

如果咱們顯式地將這兩個常量指定為非擴充套件型別,則protocols陣列將被推斷為型別("http" | "https")[],它表示一個數組,其中僅包含字串"http"或"https":

const http: "http" = "http"; // Type "http" (非擴充套件)
const https: "https" = "https"; // Type "https" (非擴充套件

const protocols = [http, https]; // Type ("http" | "https")[]

const first = protocols[0]; // Type "http" | "https"
const second = protocols[1]; // Type "http" | "https"

現在first和second的型別被推斷為"http" | "https"。這是因為陣列型別沒有對索引0處的值"http"和索引1處的值"https"進行編碼。它只是宣告該陣列只包含兩個字面量型別的值,不管在哪個位置。

如果出於某種原因,希望保留陣列中字串字面量型別的位置資訊,可以用如下的方式顯示指定:

const http = "http"; // Type "http" (可擴充套件)
const https = "https"; // Type "https" (可擴充套件)

const protocols: ["http", "https"] = [http, https]; // Type ["http", "https"]

const first = protocols[0]; // Type "http" (非擴充套件)
const second = protocols[1]; // Type "https" (非擴充套件)

現在,first和second被推斷為各自的非擴充套件字串字面量型別。

無型別匯入

從TypeScript 2.1 開始處理無型別化匯入更加容易。以前,編譯器過於嚴格,當匯入一個沒有附帶型別定義的模組時,會出現一個錯誤:

從 TypeScript 2.1 開始,如果模組沒有型別宣告,編譯器將不再報錯。

現在,匯入的range函式的型別為any。這樣做的好處是,將現有的js專案遷移到 TypeScrip t可以減少編譯時錯誤。缺點是,不會得到任何自動完成建議或細粒度型別檢查,因為編譯器對模組或其匯出一無所知。

如果過後提供型別宣告,例如通過npm的型別宣告包,它們將優先於預設的任何型別。(否則,將無法為匯入的模組提供型別)

對於沒有宣告檔案的模組的匯入,在使用了--noImplicitAny編譯引數後仍將被標記為錯誤。

// Succeeds if `node_modules/asdf/index.js` exists
import { x } from "asdf";

支援--target ES2016,--target ES2017和--target ESNext

TypeScript 2.1支援三個新的編譯版本值--target ES2016,--target ES2017和--target ESNext。

使用target--target ES2016將指示編譯器不要編譯ES2016特有的特性,比如**操作符。

同樣,--target ES2017將指示編譯器不要編譯ES2017特有的特性像async/await。

--target ESNext則對應最新的ES提議特性支援.

改進any型別推斷

以前,如果 TypeScript 無法確定變數的型別,它將選擇any型別。

let x;      // 隱式 'any'
let y = []; // 隱式 'any[]'

let z: any; // 顯式 'any'.

使用TypeScript 2.1,TypeScript 不是僅僅選擇any型別,而是基於你後面的賦值來推斷型別。

僅當設定了--noImplicitAny編譯引數時,才會啟用此選項。

示例

let x;

// 你仍然可以給'x'賦值任何你需要的任何值。
x = () => 42;

// 在剛賦值後,TypeScript 2.1 知道'x'的型別是'() => number'。
let y = x();

// 感謝,現在它會告訴你,你不能新增一個數字到一個函式console.log(x + y);
//          ~~~~~
// 錯誤!運算子 '+' 不能應用於型別`() => number`和'number'。

// TypeScript仍然允許你給'x'賦值你需要的任何值。
x = "Hello world!";

// 並且現在它也知道'x'是'string'型別的!
x.toLowerCase();

現在對空陣列也進行同樣的跟蹤。

沒有型別註解並且初始值為[]的變數被認為是一個隱式的any[]變數。變數會根據下面這些操作x.push(value)、x.unshift(value)或x[n] = value向其中新增的元素來不斷改變自身的型別。

function f1() {
    let x = [];
    x.push(5);
    x[1] = "hello";
    x.unshift(true);
    return x;  // (string | number | boolean)[]
}

function f2() {
    let x = null;
    if (cond()) {
        x = [];
        while (cond()) {
            x.push("hello");
        }
    }
    return x;  // string[] | null
}

資源搜尋網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com

隱式 any 錯誤

這樣做的一個很大的好處是,當使用--noImplicitAny執行時,你將看到較少的隱式any錯誤。隱式any錯誤只會在編譯器無法知道一個沒有型別註解的變數的型別時才會報告。

示例

function f3() {
    let x = [];  // 錯誤:當變數'x'型別無法確定時,它隱式具有'any[]'型別。
    x.push(5);
    function g() {
        x;    // 錯誤:變數'x'隱式具有'any【】'型別。
    }
}