TS -- (3)聲明文件、內置對象、類型別名、字符串字面量類型、元組、枚舉


2019-10-28:

學習內容:聲明文件、內置對象、類型別名、字符串字面量類型、元組、枚舉

補充:

(1)搜索需要的聲明文件:https://microsoft.github.io/TypeSearch/

 


 

一、聲明文件:

  使用第三方庫時,我們需要引用它的聲明文件,才能獲得對應的代碼補全、接口提示等功能。

(1)聲明語句:

  假如我們想使用第三方庫 jQuery,一種常見的方式是在 html 中通過 <script>標簽引入 jQuery,然后就可以使用全局變量 $或 jQuery了。但是在 ts 中,編譯器並不知道 $或 jQuery是什么東西。這時,我們需要使用 declare var來定義它的類型:

declare var jQuery: (selector: string) => any;

jQuery('#foo');


// declare var 並沒有真的定義一個變量,只是定義了全局變量 jQuery 的類型,僅僅會用於編譯時的檢查,在編譯結果中會被刪除。它編譯結果是:jQuery('#foo');

 

(2)聲明文件:

  通常我們會把聲明語句放到一個單獨的文件(jQuery.d.ts)中,這就是聲明文件

  聲明文件必需以 .d.ts為后綴。

  ts 會解析項目中所有的 *.ts文件,當然也包含以 .d.ts結尾的文件。所以當我們將 jQuery.d.ts放到項目中時,其他所有 *.ts文件就都可以獲得 jQuery的類型定義了。

  假如是通過模塊導入的方式使用第三方庫的話,那么引入聲明文件又是另一種方式了。

 

(3)第三方聲明文件(常用):

  jquery的聲明文件:https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jquery/index.d.ts

  使用 @types統一管理第三方庫的聲明文件。

  @types的使用方式很簡單,直接用 npm 安裝對應的聲明模塊即可,以 jQuery 舉例:npm install @types/jquery --save-dev

  這個鏈接搜索需要的聲明文件:https://microsoft.github.io/TypeSearch/

*搜索結果舉例:

 

(4)如何書寫聲明文件:這里不做記錄,詳情請看:https://ts.xcatliu.com/basics/declaration-files

 


  

二、內置對象:

  內置對象是指根據標准在全局作用域(Global)上存在的對象。這里的標准是指 ECMAScript 和其他環境(比如 DOM)的標准。

 

(1)ECMAScript 標准提供的內置對象有:BooleanErrorDateRegExp等。TS中可以直接使用

let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;

 

(2)DOM 和 BOM 提供的內置對象有:DocumentHTMLElementEventNodeList等。

let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
  // Do something
});

 

(3)TS核心庫的定義文件:

  TypeScript 核心庫的定義文件中定義了所有瀏覽器環境需要用到的類型,並且是預置在 TypeScript 中的。當你在使用一些常用的方法的時候,TypeScript 實際上已經幫你做了很多類型判斷的工作了。

舉例:

Math.pow(10, '2');

// index.ts(1,14): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'


interface Math {
    /**
     * Returns the value of a base expression taken to a specified power.
     * @param x The base value of the expression.
     * @param y The exponent value of the expression.
     */ pow(x: number, y: number): number;
}

 

  注意:TypeScript 核心庫的定義中不包含 Node.js 部分

 


 

三、類型別名:

  類型別名用來給一個類型起個新名字。

 

 

 

四、字符串字面量類型:

  字符串字面量類型用來約束取值只能是某幾個字符串中的一個。

type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
    // do something
}

handleEvent(document.getElementById('hello'), 'scroll');  // 沒問題
handleEvent(document.getElementById('world'), 'dbclick'); // 報錯,event 不能為 'dbclick'

// index.ts(7,47): error TS2345: Argument of type '"dbclick"' is not assignable to parameter of type 'EventNames'.

  注意,類型別名與字符串字面量類型都是使用 type進行定義

 


 

五、元組:

  數組合並了相同類型的對象,而元組(Tuple)合並了不同類型的對象。

  元組起源於函數編程語言(如 F#),這些語言中會頻繁使用元組。

例子1: 給元組賦值

// 直接賦值:需要提供所有元組類型中指定的項
let tom: [string, number] = ['Tom', 25];

// 分開賦值:可以只賦值其中一項
let tom: [string, number];
tom[0] = 'Tom';
tom[1] = 25;

tom[0].slice(1);
tom[1].toFixed(2);

 

例子2: 越界的元素(大於定義的數量,這些元素只能符合聯合類型)

let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);

// Argument of type 'true' is not assignable to parameter of type 'string | number'.

 


 

六、枚舉(Enum):

(1)普通枚舉(數字枚舉,字符串枚舉):

  枚舉(Enum)類型用於取值被限定在一定范圍內的場景,比如一周只能有七天,顏色限定為紅綠藍等

例子1: 使用枚舉及編譯結果

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true

console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true


// 編譯結果:
var Days;
(function (Days) {
    Days[Days["Sun"] = 0] = "Sun";
    Days[Days["Mon"] = 1] = "Mon";
    Days[Days["Tue"] = 2] = "Tue";
    Days[Days["Wed"] = 3] = "Wed";
    Days[Days["Thu"] = 4] = "Thu";
    Days[Days["Fri"] = 5] = "Fri";
    Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));

 

例子2: 手動賦值

enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true

// 未手動賦值的枚舉項會接着上一個枚舉項遞增。
// 如果未手動賦值的枚舉項與手動賦值的重復了,TypeScript 是不會察覺到這一點的

enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 3); // true
console.log(Days["Wed"] === 3); // true
console.log(Days[3] === "Sun"); // false
console.log(Days[3] === "Wed"); // true

  遞增到 3的時候與前面的 Sun的取值重復了,但是 TypeScript 並沒有報錯,導致 Days[3]的值先是 "Sun",而后又被 "Wed"覆蓋了。

// 編譯結果:

var Days;
(function (Days) {
    Days[Days["Sun"] = 3] = "Sun";
    Days[Days["Mon"] = 1] = "Mon";
    Days[Days["Tue"] = 2] = "Tue";
    Days[Days["Wed"] = 3] = "Wed";
    Days[Days["Thu"] = 4] = "Thu";
    Days[Days["Fri"] = 5] = "Fri";
    Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));

  注意:最好不要出現這種覆蓋的情況。

 

例子3: 手動賦值可以不是數字

enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};

// 編譯后:
var Days;
(function (Days) {
    Days[Days["Sun"] = 7] = "Sun";
    Days[Days["Mon"] = 8] = "Mon";
    Days[Days["Tue"] = 9] = "Tue";
    Days[Days["Wed"] = 10] = "Wed";
    Days[Days["Thu"] = 11] = "Thu";
    Days[Days["Fri"] = 12] = "Fri";
 Days[Days["Sat"] = "S"] = "Sat";
})(Days || (Days = {}));

 

例子4: 手動賦值的枚舉項也可以為小數或負數,此時后續未手動賦值的項的遞增步長仍為 1

enum Days {Sun = 7, Mon = 1.5, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1.5); // true
console.log(Days["Tue"] === 2.5); // true
console.log(Days["Sat"] === 6.5); // true

 

(2)枚舉項的兩種類型:

  常數項(constant member)和計算所得項(computed member)

  前面的例子都是常數項,一個典型的計算所得項例子:

enum Color {Red, Green, Blue = "blue".length};

  但是,如果緊接在計算所得項后面的是未手動賦值的項,那么它就會因為無法獲得初始值而報錯。計算所得項要放最后。

 

《中文手冊》:

當滿足以下條件時,枚舉成員被當作是常數:

  • 不具有初始化函數並且之前的枚舉成員是常數。在這種情況下,當前枚舉成員的值為上一個枚舉成員的值加 1。但第一個枚舉元素是個例外。

    如果它沒有初始化方法,那么它的初始值為 0

  • 枚舉成員使用常數枚舉表達式初始化。常數枚舉表達式是 TypeScript 表達式的子集,它可以在編譯階段求值。

    當一個表達式滿足下面條件之一時,它就是一個常數枚舉表達式:

    • 數字字面量

    • 引用之前定義的常數枚舉成員(可以是在不同的枚舉類型中定義的)如果這個成員是在同一個枚舉類型中定義的,可以使用非限定名來引用

    • 帶括號的常數枚舉表達式

    • +-~一元運算符應用於常數枚舉表達式

    • +-*/%<<>>>>>&|^二元運算符,常數枚舉表達式做為其一個操作對象。若常數枚舉表達式求值后為 NaN 或 Infinity,則會在編譯階段報錯

  所有其它情況的枚舉成員被當作是需要計算得出的值。

 

(3)常數枚舉(const 枚舉):

  常數枚舉與普通枚舉的區別是,它會在編譯階段被刪除,並且不能包含計算成員。為了避免在額外生成的代碼上的開銷和額外的非直接的對枚舉成員的訪問

  使用 const enum定義。

  常量枚舉只能使用常量枚舉表達式,並且不同於常規的枚舉,它們在編譯階段會被刪除。 常量枚舉成員在使用的地方會被內聯進來。 之所以可以這么做是因為,常量枚舉不允許包含計算成員。

例子:

const enum Directions {
    Up,
    Down,
    Left,
    Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];


// 編譯結果為:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

 

(4)外部枚舉:

  外部枚舉與聲明語句一樣,常出現在聲明文件中。

  使用 declare enum定義。declare定義的類型只會用於編譯時的檢查,編譯結果中會被刪除。

declare enum Directions {
    Up,
    Down,
    Left,
    Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];


// 編譯結果:
var directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

- const和declare同時使用也是可以的:

declare const enum Directions {
    Up,
    Down,
    Left,
    Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

// 編譯結果:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM