為vue3學點typescript, 基礎型別和入門高階型別

鐵皮飯盒發表於2019-07-02

直達

第一課, 體驗typescript

第二課, 基礎型別和入門高階型別

第三課, 泛型

第四課, 解讀高階型別

第五課, 名稱空間(namespace)是什麼

特別篇, 在vue3?原始碼中學會typescript? - "is"

第六課, 什麼是宣告檔案(declare)? ? - 全域性宣告篇

很重要

這一節很重要, 可以說是ts的最核心部分, 這一節學完其實就可以開始用ts寫程式碼了, 想想typescript中的type, 再看看標題中的"型別"2字, 所以請大家務必認真.

什麼是入門高階型別

因為高階型別的內容比較多, 但是有些基礎型別的知識點還必須要用到高階型別的知識講解才連貫, 所以本節課把最常用的高階型別提前講解一下, 比如介面/聯合型別/交叉型別.

基礎型別

ts中基礎型別有如下幾種:boolean / number / string / object / 陣列 / 元組 / 列舉 / any / undefined / null / void / never, 下面我們一一舉例學習:

補充說明: 上面列出的型別, 是ts中表示型別的關鍵字, 其中object其實是包含陣列/元祖/列舉, 在ts的概念中, 這個叫做型別相容, 就是說陣列型別資料, 也可以用object來標註:

let array:object = [12,321];
複製程式碼

字面量

介紹型別前,有一個前置知識點就是字面量, 字面量的意思就是直接宣告, 而非new關鍵詞例項化出來的資料:

// 字面量
const n:number = 123;
const s:string = '456';
const o:object = {a:1,b:'2'};

// 非字面量
const n:Number = new Number(123);
const s:String = new String('456');
const o:Object = new Object({a:1,b:'2'});
複製程式碼

通過上面的例子, 大家應該看明白為什麼ts中有些型別的開頭字母是小寫的了吧. 這是因為ts中用小寫字母開頭的型別代表字面量, 大寫的是用來表示通過new例項化的資料.

boolean

布林型別, 取值只有true / false

const IS_MOBILE:boolean = true;
const IS_TABLE:boolean = false;
複製程式碼

number

數字型別, 整數/小數都包括, 同時支援2/8/10/16進位制字面量.

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
複製程式碼

string

字串型別

let s1:string = 'hello world!';
let s2:string = 'hello ${name}`;
複製程式碼

陣列

陣列有2種表示方式:

第1種, 通過在指定型別後面增加[], 表示該陣列內的元素都是該指定型別:

let numbers:number[] = [1,2,3,4,5];
// number|string代表聯合型別, 下面的高階型別中會講
let numbers:(number|string)[] = [1,2,3,4,'5'];
複製程式碼

第2種, 通過泛型表示, Array<元素型別>, 泛型會在後面課講解, 先做了解即可:

let numbers:Array<number> = [1,2,3,4,5];
複製程式碼

元組(Tuple)

元組型別表示一個已知元素數量型別陣列, 各元素的型別不必相同:

let list1:[number, string] = [1, '2', 3]; // 錯誤, 數量不對, 元組中只宣告有2個元素
let list2:[number, string] = [1, 2]; // 錯誤, 第二個元素型別不對, 應該是字串'2'
let list3:[number, string] = ['1', 2]; // 錯誤, 2個元素的型別顛倒了
let list4:[number, string] = [1, '2']; // 正確
複製程式碼

列舉(enum)

列舉是ts中有而js中沒有的型別, 編譯後會被轉化成物件, 預設元素的值從0開始, 如下面的Color.Red的值為0, 以此類推Color.Green為1, Color.Blue為2:

enum Color {Red, Green, Blue}
// 等價
enum Color {Red=0, Green=1, Blue=2}
複製程式碼

當然也可以自己手動賦值:

enum Color {Red=1, Green=2, Blue=4}
複製程式碼

並且我們可以反向通過值得到他的鍵值:

enum Color {Red=1, Green=2, Blue=4}
Color[2] === 'Green' // true
複製程式碼

看下編譯成js後的列舉程式碼, 你就明白為什麼可以反向得到鍵值:

var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Green"] = 1] = "Green";
    Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
// Color的值為: {0: "Red", 1: "Green", 2: "Blue", Red: 0, Green: 1, Blue: 2}
複製程式碼

any(任意型別)

any代表任意型別, 也就是說, 如果你不清楚變數是什麼型別, 就可以用any進行標記, 比如引入一些比較老的js庫, 沒有宣告型別, 使用的時候就可以標記為any型別, 這樣ts就不會提示錯誤了. 當然不能所有的地方都用any, 那樣ts就沒有使用的意義了.

let obj:any = {};
// ts自己推導不出forEach中給obj增加了'a'和'b'欄位.
['a', 'b'].forEach(letter=>{
    obj[letter] = letter;
});

// 但是因為標記了any, 所以ts認為a可能存在
obj.a = 123
複製程式碼

void

void的意義和any相反, 表示不是任何型別, 一般出現在函式中, 用來標記函式沒有返回值:

function abc(n:number):void{
    console.log(n);
}
複製程式碼

void型別對應2個值, 一個是undefined,一個null:

const n1:void = undefined;
const n2:void = null;
複製程式碼

null 和 undefined

預設情況下null和undefined是所有型別的子型別, 比如:

const n1:null = 123;
const n2:undefined = '123';
複製程式碼

注意: 這是因為預設情況下的編譯選項strictNullChecks為false, 但是為了避免一些奇怪的問題出現, 我還是建議大家設定為true(編譯選項設定的內容, 會在後面的課程講解), 請用精準的型別去標註.

如果一個變數的值確實需要是null或者undefined, 可以像下面這麼用, ts會自動根據if/else推匯出正確型別:

// 這是"聯合型別", 在"高階型別"中會有詳細介紹, 表示n可能是undefined也可能是number
let num: undefined|number;

if(Math.random()>0.5) num = 1;

if(undefined !== num) {
    num++;
}
複製程式碼

never

never表示不可達, 用文字還真不好描述, 主要使用在throw的情況下:

function error():never{
    throw '錯了!';
}
複製程式碼

object

object表示非原始型別, 也就是除number/ string/ boolean/ symbol/ null/ undefined之外的型別:

let o1:object = [];
let o2:object = {a:1,b:2};
複製程式碼

但是, 我們實際上基本不用object型別的, 因為他標註的非常不具體, 一般都用介面來標註更具體的物件型別, 請繼續看下面的介面的內容.

高階型別入門

通過基礎型別組合而來的, 我們可以叫他高階型別. 包含: 交叉型別 / 聯合型別 / 介面等等, 當然不止他們3個, 為了不讓本節課太長造成讀者疲勞, 本節只先講這3個, 不過不要著急, 下節課會完結高階型別.

介面(interface)

一種定義複雜型別的格式, 比如我們用物件格式儲存一篇文章, 那麼就可以用介面定義文章的型別:

interface Article {
    title: string;
    count: number;
    content:string;
    fromSite: string;
}

const article: Article = {
    title: '為vue3學點typescript(2), 型別',
    count: 9999,
    content: 'xxx...',
    fromSite: 'baidu.com'
}
複製程式碼

在這種情況下,當我們給article賦值的時候, 如果任何一個欄位沒有被賦值或者欄位對應的資料型別不對, ts都會提示錯誤, 這樣就保證了我們寫程式碼不會出現上述的小錯誤.

非必填(?)

還是上面的例子, fromSite的意思是文章來自那個網站,如果文章都是原創的, 該欄位就不會有值, 但是如果我們不傳又會提示錯誤, 怎麼辦? 這時候就需要標記fromSite欄位為非必填, 用"?"標記:

interface Article {
    title: stirng;
    count: number;
    content:string;
    fromSite?: string; // 非必填
}

// 不會報錯
const article: Article = {
    title: '為vue3學點typescript(2), 型別',
    count: 9999,
    content: 'xxx...',
}
複製程式碼

用介面定義函式

介面不僅可以定義物件, 還可以定義函式:

// 宣告介面
interface Core {
    (n:number, s:string):[number,string]
}

// 宣告函式遵循介面定義
const core:Core = (a,b)=>{
    return [a,b];
}
複製程式碼

用介面定義類

先簡單看下如何給類定義介面, 後面的課程具體講類:

// 定義
interface Animal {
    head:number;
    body:number;
    foot:number;
    eat(food:string):void;
    say(word:string):string;
}

// implements
class Dog implements Animal{
    head=1;
    body=1;
    foot=1;
    eat(food:string){
        console.log(food);
    }
    say(word:string){
        return word;
    }
}
複製程式碼

交叉型別(&)

交叉型別是將多個型別合併為一個型別, 表示"並且"的關係,用&連線多個型別, 常用於物件合併:

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

const a:A = {a:1};
const b:B = {b:'1'};
const ab:A&B = {...a,...b};
複製程式碼

聯合型別(|)

聯合型別也是將多個型別合併為一個型別, 表示""的關係,用|連線多個型別:

function setWidth(el: HTMLElement, width: string | number) {
    el.style.width = 'number' === typeof width ? `${width}px` : width;
}
複製程式碼

注意: 我這裡標記了el為HTMLElement, 可以在typescript的倉庫看到ts還定義了很多元素, 請自行瀏覽(不用背, 用的時候現查), github.com/microsoft/T…

總結

如果您看完了上面的所有知識點, 你就可以開始動手造輪子練習了, 加油. 下面是我用ts造的輪子, 如果喜歡請幫忙點下star, 謝謝.

手勢庫: github.com/any86/any-t…

命令式呼叫vue元件: github.com/any86/vue-c…

工作中常用的一些程式碼片段: github.com/any86/usefu…

一個mini的事件管理器: github.com/any86/any-e…

微信群

感謝大家的閱讀, 如有疑問可以加群?, 群裡有好多有趣的前端的小夥伴, 讓我們共同學習成長吧!

可加我微信, 我拉你進入微信群(由於騰訊對微信群的100人限制, 超過100人後必須由我拉進去)

為vue3學點typescript, 基礎型別和入門高階型別

相關文章