typescript物件、陣列、函式的型別詳解
一、物件的型別:介面
概述:在面嚮物件語言中,介面(Interfaces)是一個很重要的概念,它是對行為的抽象,而具體如何行動需要由類(classes)去實現(implements)
1.介面使用
這個例子中定義了一個介面 Person,接著定義了一個變數 tom,它的型別是 Person。這樣,我們就約束了 tom 的形狀必須和介面 Person 一致
//正確使用 interface Person { name: string; age: number; } let tom: Person = { name: 'Tom', age: 25 }; // 錯誤案例一:定義的變數的屬性比介面少 interface Person { name: string; age: number; } let tom: Person = { name: 'Tom' }; // error : Property 'age' is missing in type '{ name: string; }' // 錯誤案例二:定義的變數的屬性比介面多 interface Person { name: string; age: number; } let tom: Person = { name: 'Tom', age: 25, gender: 'male' }; // error: 'gender' does not exist in type 'Person'.
結論:賦值的時候,變數的形狀必須和介面的形狀保持一致
2.可選屬性:
//可選屬性案例一:正確使用 interface Person { name: string; age?: number; } let tom: Person = { name: 'Tom' }; // ok let tony: Person = { name: Tony, age: 25}; // ok //可選屬性案例二:錯誤使用 interface Person { name: string; age?: number; } let tom: Person = { name: 'Tom', age: 25, gender: 'male' }; //error: 'gender' does not exist in type 'Person'
結論:可選屬性的含義是該屬性可以不存在,但仍然不允許新增未定義的屬性
3.任意屬性:
//任意屬性案例一:正確使用 //使用 [propName: string] 定義了任意屬性取 string 型別的值 interface Person { name: string; age?: number; [propName: string]: any; } let tom: Person = { name: 'Tom', gender: 'male' }; //任意屬性使用:錯誤使用 interface Person { name: string; age?: number; // error:型別'number'的屬性'age'不能分配給字串索引型別'string',型別'number'不能分配給'string'型別 [propName: string]: string; } let tom: Person = { name: 'Tom', age: 25, gender: 'male' };
結論:一旦在介面中定義了任意屬性,那麼確定其中和它並列的屬性和可選屬性都必須是它的子屬性
4.只讀屬性:
概述:有時候我們希望物件中的一些欄位只能在建立的時候被賦值,那麼可以用 readonly 定義只讀屬性
// 錯誤案例使用一:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
id: 89757,
name: 'Tom',
gender: 'male'
};
tom.id = 9527; // error: 無法分配給'id',因為它是常量或只讀屬性
//錯誤案例使用二:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
// 在賦值的時候,屬性id需要被初始化
// error1: Property 'id' is missing in type '{ name: string; gender: string; }
let tom: Person = {
name: 'Tom',
gender: 'male'
};
tom.id = 89757; //error2: Cannot assign to 'id' because it is a constant or a read-only property
結論(注意):只讀的約束存在於第一次給物件賦值的時候,而不是第一次給只讀屬性賦值的時候
二、陣列的型別
1.「型別 + 方括號」表示法
//ok(注意:陣列的每一項型別必須保持一致)
let fibonacci: number[] = [1, 1, 2, 3, 5];
//error: Type '(string | number)[]' is not assignable to type 'number[]'
let fibonacci: number[] = [1, '1', 2, 3, 5];
//error: Argument of type '"8"' is not assignable to parameter of type 'number'.
let fibonacci: number[] = [1, 1, 2, 3, 5];
fibonacci.push('8');
2.陣列泛型表示法
//ok (其注意事項與上面的基本表示保持一致)
let fibonacci: Array<number> = [1, 2, 2, 3, 5];
fibonacci.unshift(10);
3.陣列介面表示法
// NumberArray 表示:只要 index 的型別是 number,那麼值的型別必須是 number
interface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
4.any在陣列中的運用
let list: any[] = ['Xcat Liu', 25, { website: 'http://xcatliu.com' }];
5.類陣列:arguments、NodeList、HTMLCollection等
function sum() {
let args: NodeList = document.getElementsByTagName('a');
}
三、函式的型別(* 核心)
1.函式的宣告(包括函式宣告和函式表示式)
//函式宣告
function sum(x: number, y: number): number {
return x + y;
}
//函式表示式
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
批註:(1)輸入多餘的(或者少於要求的)引數,是不被允許的(2)在 TypeScript 的型別定義中,=> 用來表示函式的定義,左邊是輸入型別,需要用括號括起來,右邊是輸出型別。
2.使用介面定義函式的形狀
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
3.定義函式可選引數
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
批註:可選引數必須接在必需引數後面。換句話說,可選引數後面不允許再出現必須引數了。
4.設定函式引數預設值
function buildName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
5.多個不確定剩餘引數
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
6.函式的過載
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 會優先從最前面的函式定義開始匹配,所以多個函式定義如果有包含關係,需要優先把精確的定義寫在前面。