一,TS的數據類型
ES6的數據類型:
6種基本數據類型
Boolean
Number
String
Symbol
undefined
null
3種引用類型
Array
Function
Object
TS的數據類型:
TS在ES6基礎上,又新增了以下數據類型
void any never 元組 枚舉 高級類型
除此之外,TS還有很多類型的高級使用技巧
二,類型注解
TS可以通過類型注解對變量類型進行約束
TS和JS最主要的區別:變量的數據類型不可改變
語法: 變量/函數 : type
如: let hello : string = 'Hello TypeScript'
三,原始類型
let bl: boolean = true let num: number = 123 let str: string = "123"
使用類型注解對變量進行類型約束后,再進行不恰當的賦值就會報錯
四,數組類型
在 TypeScript 中,數組類型有多種定義方式,主要有一下三種定義方法:
1、「類型 + 方括號」表示法
let tsArray: number[] = [1,1,2,3,4]
數組中的項中不允許出現其他類型
let fibonacci: number[] = [1, '1', 2, 3, 5]; //報錯
上例中,
[1, '1', 2, 3, 5]
的類型被推斷為 (number | string)[]
,這是聯合類型和數組的結合。
數組的一些方法的參數也會根據數組在定義時約定的類型進行限制:
let fibonacci: number[] = [0, 1, 2, 3, 5]; fibonacci.push('6'); // index.ts(2,16): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
上例中,
push
方法只允許傳入 number
類型的參數,但是卻傳了一個 string
類型的參數,所以報錯了。
2、數組泛型
使用數組泛型(Array Generic)
Array<elemType>
來表示數組:
let arrType: Array<number> = [0, 1, 2, 3, 5]; let arrType1: Array<string> = ['0', '1', '2', '3', '5']; let arrType2: Array<any> = [1, '1', 2, 's', true];
3、
用接口表示數組
interface Person{ name: string; age: number; } interface NumberArray { [index:number]: Person; } let arrType3: NumberArray = [{name:'張三',age: 20}] let arrType4:Array<Person> = [{name:'張三',age: 20}] let arrType5:Person[] = [{name:'張三',age: 20}]
NumberArray
表示:只要 index
的類型是 number
,那么值的結構類型必須是符合Person接口。
類數組(特別注意)
類數組(Array-like Object)不是數組類型,比如 arguments
:
function sum() { let args: number[] = arguments; } // index.ts(2,7): error TS2322: Type 'IArguments' is not assignable to type 'number[]'. // Property 'push' is missing in type 'IArguments'.
事實上常見的類數組都有自己的接口定義,如 IArguments
, NodeList
, HTMLCollection
等:
function sum() { let args: IArguments = arguments; }
五,元組類型
是一種限制數組的元素類型和個數的數組
let tuple: [number, string] = [0, '1']
此時,如果改變數組的元素類型或添加元素數量,編輯器都會報錯:
let tuple: [number, string] = [0, 1] //Type 'number' is not assignable to type 'string'. let tuple: [number, string] = [0, '1', '2'] //報錯: Type '[number, string, string]' is not assignable to type '[number, string]'. Types of property 'length' are incompatible. Type '3' is not assignable to type '2'.
元組越界問題:
雖然元組限制了數組元素的類型和數量,過多的元素聲明會報錯
但TS允許向元組中使用數組的push方法插入新元素(但不允許訪問)
let tuple: [number, string] = [0, '1'] tuple.push(2) console.log("tuple.push(2)", tuple) // tuple.push(2) (3) [0, "1", 2]
但不允許訪問:
tuple.push(2) // 可越界添加 tuple[2] // 不可越界訪問 //報錯: //Tuple type '[number, string]' of length '2' has no element at index '2'.
六,函數
在 JavaScript 中,有兩種常見的定義函數的方式——函數聲明(Function Declaration)和函數表達式(Function Expression):
// 函數聲明(Function Declaration) function sum(x, y) { return x + y; } // 函數表達式(Function Expression) let mySum = function (x, y) { return x + y; };
1、函數聲明
一個函數有輸入和輸出,要在 TypeScript 中對其進行約束,需要把輸入和輸出都考慮到,其中函數聲明的類型定義較簡單:
function sum(x:number,y:number):number{ return x+y }
注意,輸入多余的或者少於要求的參數,是不被允許的
sum(1, 2, 3); // index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
sum(1); // index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
2、函數表達式
如果要我們現在寫一個對函數表達式(Function Expression)的定義,可能會寫成這樣
let mySun = function(x:number,y:number):number{ return x + y }
這是可以通過編譯的,不過事實上,上面的代碼只對等號右側的匿名函數進行了類型定義,而等號左邊的 mySum
,是通過賦值操作進行類型推論而推斷出來的。如果需要我們手動給 mySum
添加類型,則應該是這樣:
let mySum(x:number,y:number)=>number = function(x:number,y:number):number{ return x+y}
注意不要混淆了 TypeScript 中的 =>
和 ES6 中的 =>
。
在 TypeScript 的類型定義中,=>
用來表示函數的定義,左邊是輸入類型,需要用括號括起來,右邊是輸出類型。
在 ES6 中,=>
叫做箭頭函數,應用十分廣泛,
3、用接口定義函數的形狀
我們也可以使用接口的方式來定義一個函數需要符合的形狀:
interface SearchFunc{ (source:string,subString:string):boolean } let mySearch:SearchFunc; mySearch = function(source: string,subString:string){ return source.search(subString) !== -1 }
函數入參
1、可選參數
前面提到,輸入多余的(或者少於要求的)參數,是不允許的。那么如何定義可選的參數呢?
與接口中的可選屬性類似,我們用 ?
表示可選的參數:
function buildName(firstName: string, lastName?: string) { if (lastName) { return firstName + ' ' + lastName; } else { return firstName; } } let tomcat = buildName('Tom', 'Cat'); let tom = buildName('Tom');
注意:可選參數必須接在必需參數后面。換句話說,可選參數后面不允許再出現必須參數了
2、參數默認值
在 ES6 中,我們允許給函數的參數添加默認值,TypeScript 會將添加了默認值的參數識別為可選參數:
function buildName(firstName:string,lastName:string='Cat'){ return firstName + ' ' + lastName; } let tomcat = buildName('Tom', 'Cat'); let tom = buildName('Tom');
此時就不受「可選參數必須接在必需參數后面」的限制了:
function buildName(firstName: string = 'Tom', lastName: string) { return firstName + ' ' + lastName; } let tomcat = buildName('Tom', 'Cat'); let cat = buildName(undefined, 'Cat');
3、剩余參數
ES6 中,可以使用 ...rest
的方式獲取函數中的剩余參數(rest 參數):
function push(array,...items){ items.forEach(function(item){ array.push(item) }) } let a = []; push(a,1,2,3)
事實上,items
是一個數組。所以我們可以用數組的類型來定義它:
function push(array:any[],...items:any[]){
items.forEach(function(item){
array.push(item);
})
}
let a = []
push(a,1,2,3)
注意:rest 參數只能是最后一個參數
重載:
重載允許一個函數接受不同數量或類型的參數時,作出不同的處理。
比如,我們需要實現一個函數 reverse
,輸入數字 123
的時候,輸出反轉的數字 321
,輸入字符串 'hello'
的時候,輸出反轉的字符串 'olleh'
。
利用聯合類型,我們可以這么實現:
function reverse(x: number | string): number | string { if (typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse().join(''); } }
然而這樣有一個缺點,就是不能夠精確的表達,輸入為數字的時候,輸出也應該為數字,輸入為字符串的時候,輸出也應該為字符串。
這時,我們可以使用重載定義多個 reverse
的函數類型:
function reverse(x: number): number; function reverse(x: string): string; function reverse(x: number | string): number | string { if (typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse().join(''); } }
上例中,我們重復定義了多次函數 reverse
,前幾次都是函數定義,最后一次是函數實現。在編輯器的代碼提示中,可以正確的看到前兩個提示。
注意:TypeScript 會優先從最前面的函數定義開始匹配,所以多個函數定義如果有包含關系,需要優先把精確的定義寫在前面。
七,對象
在JS中,可以任意修改對象屬性,TS中不允許
let obj: object = {x: 'a', y: 'b'} obj.x = 3 // Property 'x' does not exist on type 'object'.
這是因為,僅聲明了對象obj的類型注解是object,
並沒有為對象內部的具體屬性(屬性名)和類型做限制
let obj: {x: string, y: string} = {x: 'a', y: 'b'}
obj.x = 'c'
還可以使用接口的形式來規范對象,接口會在下一篇隨筆介紹。
八,Symbol
具有唯一的值
可以顯式聲明,也可直接創建
let symbol1: Symbol = Symbol() // 顯示聲明 let symbol2 = Symbol() // 直接創建 // 驗證:是否是同一個對象 console.log(symbol1 === symbol2) // fasle
九,undefined 和 null
let udf: undefined = undefined let nu: null = null
一旦聲明了undefined,就不能再被賦值為任何其他的數據類型了:
let undf: undefined = 1 // Type '1' is not assignable to type 'undefined'.
默認情況下,undefined和null也不能被賦值給任何其他類型:
// 驗證:undefined和null也能被賦值給任何其他類型 let num1: number = undefined // Type 'undefined' is not assignable to type 'number'. let num2: number = null // Type 'null' is not assignable to type 'number'.
允許undefined和null被賦值其他類型:
在TS中,undefined和null是任何類型的子類型,所以可以被賦值給其他類型
設置允許被賦值為其他類型
打開tsconfig.js,將strictNullChecks = false(默認true)
在不修改此配置的情況下,實現對undefined和null的賦值,可使用聯合類型
let num3: number | undefined | null = 111
十,void
在js中,void操作符可以使任何一個表達式返回undefined
void 0 // 將返回undefined
在TS中,void類型表示沒有返回值,沒有返回值的函數,他的類型就是void類型
// void let voidFunc = () => {}
十一,any
any:如果不指定TS的變量類型,默認為any類型,可以賦值為任何類型
let x x = 1 // 整型 x = [] // 數組 x = () => {} // 函數
不建議使用any類型,將失去使用ts的意義
十二,never
never:永遠不會有返回值的類型
1,函數拋出異常,永遠不會有返回值,類型為never
// 函數拋出異常,永遠不會有返回值,類型為never let error = () => { throw new Error('error') }
2,死循環函數永遠沒有返回值,類型為never
// 死循環函數永遠沒有返回值,類型為never let endless = () => { while(true) {} }