TypeScript之接口&函數
一、什么是接口?
在面向對象語言中,接口(Interfaces)是一個很重要的概念,它是對行為的抽象,而具體如何行動需要由類(classes)去實現(implements)。
TypeScript 中的接口是一個非常靈活的概念,除了可用於對類的一部分行為進行抽象以外,也常用於對「對象的形狀(Shape)」進行描述。
二、接口的實現
// 用接口定義對象
interface List {
name: string,
age: number, // 必選屬性
job?: string, //可選屬性,表示不是必須的參數,
readonly id: number; // readonly 只讀屬性
[ propName : string ] : any, // 任意類型
}
interface Result {
data: List[]
}
function render(result: Result){
result.data.forEach(value => {
console.log(value.id, value.name)
if(value.age){
console.log(value.age)
}
// value.id ++
})
}
let result = {
data: [
{id: 1, name: 'A', age: 12, sex: 'male'},
{id: 2, name: 'B', age: 10}
]
}
render(result)
上面例子中的就是一個接口的實例,利用接口約束了接收變量的類型,注意,在賦值時:變量的類型必須和接口的形狀保持一致。
接口類型有以下幾種屬性可選
-
必選屬性 => ":" 帶冒號的屬性是必須存在的,不可以多也不能少
-
可選屬性 => " ? " 表示有選擇的選項,可有可無
-
只讀屬性 => " readonly " 對象的字段只在創建的時候賦值,注意哦,注意,只讀的約束存在於第一次給對象賦值的時候,而不是第一次給只讀屬性賦值的時候:
-
任意屬性 [ propName : 類型 ] : any 表示定義了任意屬性取string 類型的值
三、可索引接口:數組、對象的約束(不常用)
1、對數組的約束
interface StringArray {
[index: number]: string;
} // 用任意的number去索引StringArray,最后得到的是一個字符串的數組
let chars: StringArray = ['A', 'B']
interface Names {
// [x: string]: string // 字符串索引簽名
[x: string]: any
// y: number
// [z: number]: string // 數字索引簽名
[z: number]: number
}
注:數字索引簽名的返回值一定是字符串索引簽名返回值的子類型,因為js會進行轉換,將number轉換成string,保證類型的兼容性
2、對對象的約束
interface UserObj{
[index : string] : string // 討論點:為啥一定是string,而不能是number
}
var arr : UserObj = { name : '張三' };
四、函數的定義
1、函數聲明
function add1(x: number, y: string) : string {
return x + y
}
console.log('add1', add1(3, '4'))
形式和JavaScript中的函數聲明一樣,但不一樣的是:
- 指定了參數的類型(因為有類型檢查,所以要遵循),隨后指定了返回值的類型,這個時候返回值類型可以省略,因為typescript會根據返回語句自動推斷出返回值的類型。
- 參數不可多不可少,只能剛剛好,且和順序有關。
2、函數聲明的方式有哪些?
function add1(x: number, y: string) {
return x + y
}
let add2: (x: number, y: number) => number
type add3 = (x: number, y: number) => number
interface add4 {
(x: number, y: number): number
}
3、函數表達式
1)左邊的student的類型定義是通過賦值操作進行類型推論而推斷出來的,並沒有給student指定類型定義。
let student = function(x:string,y:number):string{
return `我是${x},今年${y}歲`;
}
console.log(student("wzy",22)); // 我是wzy,今年22歲
2)如果要給student指定類型的話,應該是這樣:
let student:(x:string,y:number)=>string = function(x:string,y:number):string{
return `我是${x},今年${y}歲`;
}
console.log(student("wzy",22)); // 我是wzy,今年22歲
注:1.前后參數名稱可以不一致
2.當沒有返回值的時候使用void
4、定義一個可選參數
function add5(x : number, y ?: number){
return y ? x + y : x;
}
add5(4)
之前提到過函數的參數是不可多不可少的,但是也可以像接口那樣的形式用?表示可選參數
注:可選參數必須位於必需參數后
5、定義默認參數
function add6(x: number, y = 0, z: number, q = 1){
return x + y + z + q
}
add6(2, undefined, 4)
注:必傳參數前的默認參數必傳,如果沒有,用undefined代替
6、定義剩余參數
function add7(x : number, ...rest: number[]){ // 剩余參數,即不知道參數的個數
return x + rest.reduce((pre, cur) => pre + cur)
}
console.log(add7(1,2,3,4,5))
當你想同時操作多個參數或者你並不知道會有多少個參數會傳進來時可以采用剩余參數定義
-
在JavaScript中,可以使用arguments來訪問所有傳入的參數。
-
在typescript里,可以把所有參數收集到一個變量里
注:
(1)剩余參數會被當做個數不限的可選參數,可以一個都沒有,也可以有任意個。同樣要放在必要參數后面。
(2)是數組類型,名字是省略號后面的字段名,可以在函數體內使用這個數組。
(3)當調用函數時,別傳入數組,依次傳入就行。
7、函數重載(不需要為相似函數選取不同的函數名稱)
function add8(...rest: number[]) : number;
function add8(...rest: string[]) : string;
function add8(...rest: any[]) : any {
let first = rest[0];
if(typeof first === 'string'){
return rest.join('')
}
if(typeof first === 'number'){
return rest.reduce((pre, cur) => pre + cur)
}
}
console.log(add8(1,2,3))
console.log(add8('2','add', 'asd'))
注:TypeScript 會優先從最前面的函數定義開始匹配,所以多個函數定義如果有包含關系,需要優先把精確的定義寫在前面。