- 淺析基本數據類型
- TypeScript類型解析
一、淺析基本數據類型
首先有一個問題TypeScript是一門編譯型語言?還是解釋性語言?顯然已經不能被這兩個分類來區分,TypeScript的並不是為了讓JavaScript改變執行方式,不是為了提高機器執行效率的。而編譯型和解釋型的分類是基於這兩個特點的。但是,TypeScript具備編譯型語言一個特點,就是它對類型進行檢查,如果出現類型沖突時它是無法編譯成js文件的。
既然TypeScript編譯需要對變量進行類型檢查,這就意味着TypeScript的變量是有類型的,前面這句話可能會讓你很疑惑,難道再TypeScript之前的JavaScript沒有類型嗎?String、Number、boolean等不是類型嗎?
JavaScript的變量本身確實是不存在類型的概念,而僅僅只是變量的值存在類型,變量本身的類型隨着值的類型發生改變。而TypeScript的變量是有類型的,並且它的類型不再隨着值的類型發生改變,有錯誤檢查的編輯器中出現了變量類型與值類型不一致時會提示錯誤,這一點是理解TypeScript的關鍵,非常重要。
TypeScript的基本類型包括:布爾值、數字、字符串、數組、元組、枚舉、Any、Void、Null、Undefined、Never、Object。
在進行接下來的內容之前建議了解以下內容
JavaScript的嚴格模式,相關博客:JavaScript嚴格模式
JavaScript的類型轉換,相關博客:類型和原生函數及類型轉換(三:終結js類型轉換)
ES6變量聲明:ES6入門一:塊級作用域(let&const)、spread展開、rest收集
更多關於ES6語法可以了解這里:關於ES6語法與API的全部解析內容
建議閱讀TtpeScript的變量聲明文檔(其簡要的解析了ES5與ES6的變量聲明相關內容):變量聲明官方文檔
二、TypeScript類型解析
1.TypeScript基本數據類型:
TypeScript數據類型是用來描述變量本身的,然后用變量本身的類型約束值的類型,當值的類型不匹配變量本身的類型時,IDE就會提示錯誤。
1.1布爾值、數字、字符串變量的聲明方式語法:
let 變量名稱 :變量類型 = 值 ;//值的類型必須與變量類型一致,否則提示錯誤
示例:
1 let isDone: boolean = false; 2 let decLiteral: number = 6; 3 let hexLiteral: number = 0xf00d; //16進制 4 let binaryLiteral: number = 0b1010; //二進制 5 let octalLiteral: number = 0o744; //8進制 6 let name: string = "bob";
定義模板字符串:
1 let name: string = `Gene`; 2 let age: number = 37; 3 //模板字符串使用反引號(`)包裹,使用${expr}嵌入表達式 4 let sentence: string = `Hello, my name is ${ name }. 5 I'll be ${ age + 1 } years old next month.`;
1.2數組、元組、枚舉
1 //數組 2 let list: number[] = [1,2,3];//list變量是一個數組,只要賦值數組就沒問題 3 let numList: Array<number> = [1,2,3];//泛型數組,賦值的數組每個元素類型必須符合指定的泛型類型 4 let strList: Array<string> = ["1","2","3"];//這是一個字符串泛型數組
泛型數組還有一種簡寫方式:
let names:string[] = ['小明','小紅'];
關於泛型可以了解官方文檔:https://www.tslang.cn/docs/handbook/generics.html,后期也會有博客專門來解析TtpeScript泛型。
//元組:聲明數組時指定數組的每一個元素類型,並且數組長度不能超出變量聲明時指定的元素個數 let arr:[string,number] = ['1',2];
如果在給元組超出定義長度位置的元素賦值會出現錯誤提示,這個錯誤操作一般會出現兩個(2493,2322):2493提示超出元組范圍,2322提示賦值類型非undefined類型,所以如果賦值undefined不會報2322錯誤。詳細可以查看官方錯誤提示文檔:文檔/項目配置/錯誤信息列表
比如下面這樣給arr[3]賦一個非undefined值:
arr[3] = 10;
TypeScript中的枚舉(enum)非常友好的提供了一個有窮序列集的數據結構,它會默認從0開始給每個元素編號,可以通過元素獲取編號,也可以通過編號獲取元素名稱,然而其內部實現采用的是犧牲空間換時間的方式,比如枚舉Color中有一個元素Blue,底層實現方式是{Blue:0,0:'Blue'},這就實現了當要查找值對應的元素時只需要Color[0]就能獲取,而如果在前的數組或對象中要想獲得值對應的元素就只能遍歷數組或者對象來實現。
1 //枚舉 2 enum Color { 3 Red, 4 Green, 5 Blue 6 } 7 console.log(Color.Red);//0 8 //自定義編號或者值:編號只能為數值,元素為字符串 9 enum Name { 10 xiaoming = 3, 11 xiaohong = 5 12 } 13 console.log(Name[3]);//'xiaoming' 14 //枚舉同樣不能越界,只能在枚舉有限集合中查找 15 Color.Yellow = 4; //報錯(2339):類型上找不到‘Yellow’該屬性
1.3任意類型(any)與無效類型(Void)
1 //any類型:同等與JavaScript的變量,變量的類型取決於值的類型,並且可以任意變化 2 let notSure: any = 4; 3 notSure = "maybe a string instead"; 4 notSure = false;
這里可能會疑惑Any這個變量類型有什么用?這不又回到了JavaScript了嗎?的確,它可以幫助我們回歸到JavaScript變量類型模式,這就意味着我們如果在做項目升級時,在遇到無法確定的變量類型我們就可以使用Any;還有就是第三方庫或者用戶輸入的數據,我們也可能無法確定其類型,這時候就可以解決這類問題。
還有一個很關鍵的應用就是TypeScript中的數組,前面的Array語法中如果需要一個元素類型不相同的數組我們只能使用元組來實現,但是元組有約束了下標和長度,還是可能無法完成一些特殊的需求,特別是對於習慣JavaScript的寬松的數組模式,Any可以幫助TtypeScript實現同等JavaScript的數組:
let list: any[] = ['hello',100,true];
void類型用處就不大了,它用來表示沒有任何類型,其作用就是用來描述沒有類型,在一定程度上它同等與undefinde。
1 //void變量值始終為undefined 2 let a: void = undefined; 3 function foo(): void {//用來表示函數不返回任何值 4 // return void ...;以前我們可以這樣表示函數不返回任何值 5 // 之前javaScript的寫法不會有錯誤檢查,閱讀代碼時需要查看函數內部代碼 6 }
1.4 undefined、null
用來指定變量只能為undefined和null的值,undefined和null變量類型在TypeScript中還有一個含義,它們可以作為任何變量的子集,當然這時在tsconfig.json的"strictNullChecks": false的情況下。
1 let a:undefined = undefined; 2 let b:null = null; 3 let c: number = 10; 4 c = undefined; 5 c = null; 6 // tsconfig.json -- "strictNullChecks": false模式
1.5 never:用來表示那些永遠不存在的值的類型。比如拋出錯誤,這種情況通常出現在錯誤檢查中。變量也可以是never類型,但是賦值除了自身類型以外的任何變量類型都會提示錯誤。
1 interface Test { 2 imgNumberPerWork: number 3 displayCover: boolean 4 } 5 const test: Test = { 6 imgNumberPerWork: 0, 7 displayCover: true 8 } 9 function setValue (key: keyof Test, val: any) { 10 test[key] = val //Type 'any' is not assignable to type 'never' 11 } 12 setValue('imgNumberPerWork', 1)
示例中因為Test.imgNumberPerWork是數字類型,但是在setValue()中賦any類型的值。在官方文檔中有這樣一段描述,never為任何類型的字類,可以賦值給任何類型,但是never除了自身不能賦值任何類型值。
never類型的引用場景主要有:
1 //1.拋出異常 2 function error(message: string): never { 3 throw new Error(message); 4 } 5 //死循環 6 function loop(): never { 7 while (true){} 8 } 9 //never是所有類型的子集,例如作為number的子集: 10 let a: number; 11 y = (() => { throw new Error 'message' })();
1.6 對象(Object) 、對象類型(Type)
關於TypeScript的Object變量聲明:
1 let dataObject = { 2 name: "xiaoming", 3 age: 31 4 } 5 //錯誤一 6 // dataObject = {} 7 //錯誤提示:type '{}' is missing the following properties from type '{name:tring;age:number;}':name, age ts 8 // 類型“{}”缺少類型“{name:tring;age:number;}”的以下屬性:name, age ts 9 10 //錯誤二 11 // dataObject = { 12 // a: 'str' 13 // } 14 // 錯誤提示:type '{a:tring;}' is not assignable to type '{name:string;age:number}' 15 // Object literal may only specify known properties, and 'a' does not exist in type '{name:tring;age:number}' 16 // 類型“{a:tring;}”不能分配給類型“{name:string;age:number}” 17 // 對象字段只能指定已知的屬性,類型“{name:tring;age:number}”中不存在“a”
這兩個錯誤信息都提到了類型'{name:string;age:number}',這個類型的意思就是dataObject這個變量的類型,這個類型只有name、age兩個字段,並且這兩個字段分別指定了string、number類型,如果要賦值給dataObject對象值就必須是符合這個類型的。不能擅自添加字段,也不能刪除字段,所以下面這樣寫也是錯誤的:
1 //錯誤三:缺少字段 2 //dataObject = { 3 // name:'xiaohong' 4 //}
實際上,TypeScript中Object類型的變量聲明的完整方式是下面這樣的:
1 //聲明TypeScript的Object對象 2 let dataObject:{name:string;age:number} = { 3 name: "xiaoming", 4 age: 31 5 }
復雜類型的聲明與type關鍵字
1 let complex: {datas:number[]; myfunc:(item:number) => number[]} = { 2 datas:[1,2,3], 3 myfunc:function(item:number){ 4 this.datas.push(item); 5 return this.datas; 6 } 7 }
如果我們需要聲明多個相同結構的類型甚至更復雜的類型,最好的方式是將Object變量類型聲明與賦值分離,比如還以上面這個復雜的Object變量類型為例,聲明多個相同結構的Object變量:
1 //通過type關鍵字定義Object變量類型 2 type MyObject = {datas:number[]; myfunc:(item:number) => number[]} ; 3 //聲明Object變量類型為MyObject的變量 4 let complex1 : MyObject = { 5 datas:[1,2,3], 6 myfunc:function(item:number){ 7 this.datas.push(item); 8 return this.datas; 9 } 10 } 11 let complex2 : MyObject = { 12 datas:[1,2,3,5,6,7,8,9], 13 myfunc:function(item:number){ 14 this.datas.unshift(item); 15 return this.datas; 16 } 17 }
1.7 函數類型function
在前面的對象變量類型中已經有了TypeScript函數聲明的代碼,函數聲明關鍵字還是function,但需要在聲明時指定參數和返回值的類型:
1 function add1(x:number,y:number):number{ 2 return x+y; 3 } 4 5 let add2 = function(x:number,y:number):number{ 6 return x + y; 7 }
函數聲明還有一種方式,可以先聲明函數類型,在賦值函數:
1 let myAdd : (baseValue: number, increment: number) => number = 2 function(x:number,y:number) : number{ 3 return x + y; 4 }
函數類型的參數名稱和實際賦值的函數參數名稱可以不一致,但類型和參數個數必須一致。關於函數返回值在void(沒有任何類型)變量類型的時候就提到過函數不返回值的處理方式,就是將函數的返回值設置為void類型:
1 let hintStamp(str:string):void{ 2 console.log(str); 3 }
關於TypeScript中函數類型還有更多內容,這里僅僅是展示了聲明的語法,詳細關注這篇博客:(待補充)