一、前言
TS新增了一個重要概念:接口,分為對象類型接口和函數類型接口
接口可以約束對象,函數,類的結構和類型,是一種代碼協作必須遵守的契約
接口的定義方式:
使用interface關鍵字
二、對象類型接口
接口中可定義 確定屬性、可選屬性、任意屬性、只讀屬性
1、確定屬性
interface UserInfo { name: string; age: number; } const myInfo: UserInfo = { name: "haha", age: 20 };
接口中約束好的確定屬性,定義對象變量的時候 不能少也 不能多
2、可選屬性
interface UserInfo {
name: string;
age: number;
sex?:string
}
const myInfo: UserInfo = {
name: "haha",
age: 20
};
接口中的可選屬性,是表示在對象變量中可以不存在
3、任意屬性
interface UserInfo {
name: string;
age: number;
sex?:string ;
[propName: string]:any;
}
const myInfo: UserInfo = {
name: "haha",
age: 20,
test1: 'lala',
test2: 'ff',
test3:123
};
注:一旦定義了任意屬性,那么確定屬性和可選屬性的類型都必須是任意屬性類型的子類;
定義了任意屬性后,對象變量中的屬性個數才可以出現比接口的屬性數量多的情況
4、只讀屬性
interface UserInfo {
readonly id: number;
name: string;
age: number;
sex?: string;
[propName: string]: any;
}
const myInfo: UserInfo = {
id: 1,
name: "haha",
age: 20,
test1: "lala",
test2: "ff",
test3: 123
};
只讀屬性也是確定屬性,在對象變量定義的時候必須有值,此后不能修改
對象接口示例
以查詢商品列表接口API為例:
// 接口聲明:API協議約定返回格式 interface ResponseData { resCode: number; resData: ResultData[]; message: string; } // 數據接口聲明 interface ResultData { productId: number; productName: string; }
符合接口約定的對象:
let resultData = { resCode: 0, resData: [ { productId: 1, productName:"TypeScipt實戰" }, { productId: 2, productName:"TypeScipt從入門到精通" }, ], message: "success" }
輸出函數對結果進行打印:
function render(res: ResponseData) { console.log(res.resCode, res.message) res.resData.forEach((obj) => { console.log(obj.productId, obj.productName) }) } render(resultData);
輸出:
0 "success" 1 "TypeScipt實戰" 2 "TypeScipt從入門到精通"
額外屬性
在接口的實際調用中,后端也經常會傳遞約定之外的字段,比如:
let resultData = { resCode: 0, resData: [ { productId: 1, productName:"TypeScipt實戰", remark:""}, // 接口約定以外的remark字段 { productId: 2, productName:"TypeScipt從入門到精通" }, ], message: "success" }
此時,並沒有報錯,TS允許這種情況的發生
只要傳入的對象滿足接口的必要條件就可以被允許,即使傳入多余的字段也可以通過類型檢查
但也有例外,如果直接傳入對象字面量,TS就會對額外的字段進行類型檢查
以下方式會報錯:
render({
resCode: 0, resData: [ { productId: 1, productName:"TypeScipt實戰", remark: "備注"}, { productId: 2, productName:"TypeScipt從入門到精通" }, ], message: "success" })
繞過檢查的方法有3種:
1,將對象字面量賦值給一個變量
將對象字面量賦值給一個變量后,在render不再報錯:
let result = { resCode: 0, resData: [ { productId: 1, productName:"TypeScipt實戰", remark: "備注"}, { productId: 2, productName:"TypeScipt從入門到精通" }, ], message: "success" } render(result)
2,使用類型斷言
使用類型斷言方式,明確告訴編譯器類型是什么,編譯器就會繞過類型檢查
方法1:
object as targetInterface
render({ resCode: 0, resData: [ { productId: 1, productName:"TypeScipt實戰", remark:""}, { productId: 2, productName:"TypeScipt從入門到精通" }, ], message: "success" } as ResponseData)
方法二:
<targetInterface>object
render(<ResponseData>{ resCode: 0, resData: [ { productId: 1, productName:"TypeScipt實戰", remark: "備注"}, { productId: 2, productName:"TypeScipt從入門到精通" }, ], message: "success" })
3,使用字符串索引簽名
添加字符串索引簽名:
interface ResultData { productId: number; productName: string; [remark: string]: any; // 字符串索引簽名 }
表示用任意字符串去索引List,可得到任意結果,此時List可以實現支持多個屬性
三、函數接口
函數定義方式
1,在TS中,可以使用一個變量直接定義函數:
// 1,使用變量定義函數 let add: (x: number, y: number) => number
= (x, y){
return x+y; };
add(1,2)
2,還可以使用接口來定義函數:
// 2,使用接口定義函數 interface Add { (x: number, y: number): number }
let myFunc: Add = function(x, y){ return x+y; }; myFunc(1,2);
3,使用類型別名來定義函數:
類型別名使用type關鍵字,相當於為函數類型起一個名字
// 3,使用類型別名來定義函數 type Add = (x: number, y: number) => number
四、可索引類型的接口
當不能確定接口中有多少個屬性時,可以使用可索引類型接口
可索引類型接口可以用數字去索引,也可以用字符串去索引
1,數字索引接口:
聲明一個數字索引類型的接口:
表示用任意數字去索引numberIndex都會得到一個string
interface numberIndex { [x: number]: string } // 相當於聲明了一個字符串類型的數組 let chars: numberIndex = ['A', 'B']
2,字符串索引接口:
聲明一個字符串索引類型的接口:
表示用任意的字符串去索引stringIndex得到的結果都是string
interface stringIndex {
[x: string]: string
}
這樣聲明后,就不能聲明number類型的成員了,會報錯
interface stringIndex { [x: string]: string y: number;// Property 'y' of type 'number' is not assignable to string index type 'string'. }
3,兩種索引簽名混用:
在上邊的字符串索引接口stringIndex中,添加數字索引簽名
interface stringIndex {
[x: string]: string
[z: number]: string
}
這樣做.接口既可以用數字索引Names也可以用字符串索引Names
但需要注意:數字索引的返回值,一定要是字符串返回類型的子類型
這是因為JS會進行類型轉換,將number轉換成string,這樣就能保證類型的兼容性
比如:將數組索引的返回值改成number:
interface stringIndex { [x: string]: string [z: number]: number // // Numeric index type 'number' is not assignable to string index type 'string'. }
這樣就和String類型不兼容了,要取一個能夠兼容number的類型,比如any:
interface stringIndex { [x: string]: any [z: number]: number // Numeric index type 'number' is not assignable to string index type 'string'. }