1. 接口的聲明
在前面我們通過type可以用來聲明一個對象類型:
type Point = {
x: number
y: number
}
對象的另外一種聲明方式就是通過接口來聲明:
interface Point = {
x: number
y: number
}
接口類型也可以定義可選類型和只讀屬性棕叫,只讀屬性指我們再初始化之后,這個值是不可以被修改的
// 通過類型(type)別名來聲明對象類型
// type InfoType = {name: string, age: number}
// 另外一種方式聲明對象類型: 接口interface
// 在其中可以定義可選類型
// 也可以定義只讀屬性
interface IInfoType {
readonly name: string
age: number
friend?: {
name: string
}
}
const info: IInfoType = {
name: "why",
age: 18,
friend: {
name: "kobe"
}
}
console.log(info.friend?.name)
console.log(info.name)
// info.name = "123"
info.age = 20
2. 索引類型
// 通過interface來定義索引類型
interface IndexLanguage {
[index: number]: string
}
const frontLanguage: IndexLanguage = {
0: "HTML",
1: "CSS",
2: "JavaScript",
3: "Vue"
}
interface ILanguageYear {
[name: string]: number
}
const languageYear: ILanguageYear = {
"C": 1972,
"Java": 1995,
"JavaScript": 1996,
"TypeScript": 2014
}
3. 函數(shù)類型
前面我們都是通過interface來定義對象中普通的屬性和方法的奕删,實際上它也可以用來定義函數(shù)類型:
用接口定義函數(shù)類型
image.png
// type CalcFn = (n1: number, n2: number) => number
// 可調用的接口
interface CalcFn {
(n1: number, n2: number): number
}
function calc(num1: number, num2: number, calcFn: CalcFn) {
return calcFn(num1, num2)
}
const add: CalcFn = (num1, num2) => {
return num1 + num2
}
calc(20, 30, add)
4. 接口繼承
接口和類一樣是可以進行繼承的俺泣,也是使用extends關鍵字:
并且我們會發(fā)現(xiàn),接口是支持多繼承的(類不支持多繼承)
interface ISwim {
swimming: () => void;
}
interface IFly {
flying: () => void;
}
interface IAction extends ISwim, IFly {}
//支持多繼承
const action: IAction = {
swimming() {},
flying() {},
//里面必須有這兩個方法
};
image.png
5.交叉類型
image.png
6.交叉類型的應用
image.png
// 一種組合類型的方式: 聯(lián)合類型
type WhyType = number | string;
type Direction = "left" | "right" | "center";
/* ,聯(lián)合類型的話是把我們多個這個值伏钠,
多個我們的類型横漏,多個類型跟他聯(lián)合在一起,到時候的話熟掂,你取里面的任何缎浇,一個類型都可以 */
// 另一種組件類型的方式: 交叉類型
type WType = number & string;
interface ISwim {
swimming: () => void;
}
interface IFly {
flying: () => void;
}
type MyType1 = ISwim | IFly;
type MyType2 = ISwim & IFly;
const obj1: MyType1 = {
flying() {},
};
const obj2: MyType2 = {
swimming() {},
flying() {},
};
export {};
兩個接口他們的組合的時候就有兩種方式了,第一種方式的話是定義一個新的接口打掘,然后讓他們繼承自我原來的這兩個接口华畏,那么這個接口里面就相當于把前面這兩個就給他組合在一起了,另外一種方式尊蚁,交叉類型,他也是可以把我們兩個對象類型侣夷,兩個對象類型跟他結合在一起横朋,結合在一起之后的話,生成一個新的類型.
7.接口的實現(xiàn)
1.接口作為標識符的使用
interface Iswim {
swimming: () => void;
}
interface IEat {
eating: () => void;
}
//這兩個接口可以作為類型百拓,比如在定義變量的時候
const a: Iswim = {
swimming() {},
}; //接口作為標識符類型
function foo(swim: Iswim) {
//傳入的這個對象必須滿足這個接口
}
foo({ swimming() {} });
- 類可以作為接口
interface Iswim {
swimming: () => void;
}
interface IEat {
eating: () => void;
}
// 類實現(xiàn)接口
class Animal {}
//類Fish除了可以繼承Animal琴锭,也可以實現(xiàn)接口
//但是繼承的化只能實現(xiàn)單繼承
class Fish extends Animal implements ISwim, IEat {
swimming() {
console.log("Fish Swmming");
}
eating() {
console.log("Fish Eating");
}
//因為實現(xiàn)了兩個接口所以里面必須有swiming和eating
/*
使用類實現(xiàn)接口的化,編寫一一些公共的公共的API的話衙传,在很多的情況下都可以調用的决帖,對于可復用的一些API的時候,它就變得更加的靈活蓖捶。那么我們就可以面向接口進行編程地回。
*/
}
//// 編寫一些公共的API: 面向接口編程
//function swimAction(swimable: Fish {
// swimable.swimming();
//}
swimAction(new Fish());
//這么寫的話,這個函數(shù)就不具備通用性俊鱼,因為這個參數(shù)我們就只能傳Fish類型的一個對象刻像。
//如果我們想swimAction({swimming: function() {}})是不可以的。只能new一個Fish對象
//這個時候我們就可以面向接口編程
function swimAction(swimable: ISwim) {
swimable.swimming()
}
// 1.所有實現(xiàn)了接口的類對應的對象, 都是可以傳入
swimAction(new Fish())
//如果Person也實現(xiàn)了 ISwim
class Person implements ISwim {
swimming() {
console.log("Person Swimming")
}
}
swimAction(new Person())
swimAction({swimming: function() {}})
/* 就意味著只要是有一個類并闲,它實現(xiàn)了這個接口细睡,到時候的話,它都是可以調動我公共的這個API的帝火,那么我在編輯這個公共API的時候溜徙,我這里最好就是面向接口編程的
面向接口編程的話,就讓我編寫的這個API他更加具備通用性啦犀填,在很多很多地方都可以被別人調用蠢壹,只要你實現(xiàn)了我的這個接口,甚至是我們普通的對象字面量宏浩,你只要也是符合我接口對應的類型的知残,你也是可以傳到我們這個里面去的,可以轉到這個里面去,所以這個的話就叫做面向接口編程
*/
export {};
8.interface和type區(qū)別
image.png
interface IFoo {
name: string;
}
interface IFoo {
age: number;
}
/* interface允許定義兩個名字相同的接口,意味著會把兩個接口的內容合并在一起求妹,相當于
interface Ifoo {
ame: string
age: number
}
*/
const foo: IFoo = {
name: "why",
age: 18,
};
export {};
// document.getElementById("app") as HTMLDivElement
/*
剛才我們看到的Windows類型乏盐,包括document這些類型它來自哪里呢,這些類型來自于我們在安裝typescript的時候制恍,它會默認幫助我們安裝一些lib的庫父能,
那安裝的這些庫里面,它就默認有幫助我們定義很多的類型净神,
包括比如說這個javascript里面內置的一些類型項何吝,Math,Data這些類型鹃唯,包括這些內置類型爱榕,
也包括dom的一些類型的API的話,
Winodw類型坡慌,HTMLDivElement類型等
06:01
*/
//window這個類型沒有age這個屬性黔酥,我們如果想有age這個屬性的化
interface Window {
age: number;
}
//這時候不能覆蓋以前的Window,而是合并
window.age = 19;
console.log(window.age);
//type根本不允許定義兩個相同的類型
// type IBar = {
// name: string
// age: number
// }
// type IBar = {
// }
9.字面量賦值
interface IPerson {
name: string;
age: number;
height: number;
}
const info: IPerson = {
name: "why",
age: 18,
height: 1.88,
//address: "廣州市", //不能添加這個屬性洪橘,因為IPerson沒有定義
};
怎么讓他不報錯呢
interface IPerson {
name: string;
age: number;
height: number;
}
const info = {
name: "why",
age: 18,
height: 1.88,
address: "廣州市",
}; //info會做類型推導摔敛,推導出來
/*
const info: {
name: string;
age: number;
height: number;
address: string;
}
*/
const p: IPerson = info;
/*
這個時候把info類型和IPerson類型是沖突的关划,因為多了個address
ts主要做類型檢測儡首,類型檢測通過蔑鹦,你這個代碼就沒有問題
fressness擦除
當把info這個引用類型賦值給p的時候,他會把我們對應某一個屬性給它擦除掉弟晚,擦出掉之后忘衍,也就是address,如果依然是滿足你這里的這個類型的情況下指巡,也就是 IPerson 淑履,因為我們這三個是不是依然是滿足的,依然是滿足的情況下藻雪,就是可以賦值的秘噪。如果info里面沒有age,你再把這個address擦掉之后勉耀,你是少一個的指煎,少一個是不行的,同學們就是擦除掉那些多余的便斥,擦掉那些多余的之后至壤,
我依然是符合你這類型的,他是允許我們這么賦值的枢纠,它允許這么賦值
*/
console.log(info);
console.log(p);
/* { name: 'why', age: 18, height: 1.88, address: '廣州市' }
{ name: 'why', age: 18, height: 1.88, address: '廣州市' } */
export {};
這是因為TypeScript在字面量直接賦值的過程中像街,為了進行類型推導會進行嚴格的類型限制。
但是之后如果我們是將一個 變量標識符 賦值給其他的變量時,會進行freshness擦除操作镰绎。
應用
interface IPerson {
name: string;
age: number;
height: number;
}
function printInfo(person: IPerson) {
console.log(person);
// console.log(person.address);不可以使用address脓斩,因為對于類型檢測來說,畴栖,人家認為你這個person里面只有三個屬性随静,,在這里取address的時候吗讶,在類型檢測這一步他是過不去的燎猛,但是可以直接打印所有
}
// 代碼會報錯
// printInfo({
// name: "why",
// age: 18,
// height: 1.88,
// address: "廣州市"
// })
const info = {
name: "why",
age: 18,
height: 1.88,
address: "廣州市",
};
printInfo(info);
//{ name: 'why', age: 18, height: 1.88, address: '廣州市' }
export {};
10.TypeScript枚舉類型
image.png
//,其實枚舉類型就是定義一組常量照皆,并且給他放到我們對應的一種數(shù)據(jù)類型里面
// type Direction = "left" | "Right" | "Top" | "Bottom"
enum Direction {
LEFT,
RIGHT,
TOP,
BOTTOM,
} //代碼閱讀性強
/*
看起來這些東西是我們的一些標識的一些常量重绷,但是其實本質上他們是一些數(shù)字常量,也就第一個的話其實是一個零膜毁,然后第二個的話是一個一论寨,第三個的話是一個二,然后第四個的話就是一個三爽茴,它內部是由我們這里這么一些數(shù)字的值的,只不過這些值你不需要去寫绰垂,你不寫的時候室奏,他們默認也是有的,但是能改變這里這些東西的值
enum Direction {
LEFT = 0,
RIGH = 1,
TOP = 2,
BOTTOM = 3,
} 默認
enum Direction {
LEFT = 100,
RIGH = 200,
TOP = 300,
BOTTOM = 400,
}
enum Direction {
LEFT = 100,
RIGH ,//101
TOP ,//102
BOTTOM,//103
}
*/
function turnDirection(direction: Direction) {
console.log(direction);
switch (direction) {
case Direction.LEFT:
console.log("改變角色的方向向左");
break;
case Direction.RIGHT:
console.log("改變角色的方向向右");
break;
case Direction.TOP:
console.log("改變角色的方向向上");
break;
case Direction.BOTTOM:
console.log("改變角色的方向向下");
break; //如果少些一個case的化,代碼會報錯劲装。因為default用了never類型
default:
const foo: never = direction;
break;
}
}
turnDirection(Direction.LEFT);
turnDirection(Direction.RIGHT);
turnDirection(Direction.TOP);
turnDirection(Direction.BOTTOM);
export {};
/*
0
改變角色的方向向左
1
改變角色的方向向右
2
改變角色的方向向上
3
改變角色的方向向下
*/
11.枚舉類型的值
image.png