TypeScript系列文章
可瀏覽博客主頁(yè)的TypeScript專欄,會(huì)陸續(xù)添加相關(guān)文章,有問(wèn)題或者可以優(yōu)化的地方也希望大大門告知
共同進(jìn)步 :)
interface-接口
ts版本 Version 4.8.4
TypeScript的核心原則之一是對(duì)值所具有的結(jié)構(gòu)進(jìn)行類型檢查。 它有時(shí)被稱做“鴨式辨型法”或“結(jié)構(gòu)性子類型化”。 在TypeScript里,接口的作用就是為這些類型命名和為你的代碼或第三方代碼進(jìn)行類型限制。
接口可以對(duì)普通對(duì)象,函數(shù),類進(jìn)行類型限制!??!
接口實(shí)戰(zhàn)
1. 常規(guī)類型限制 vs 接口類型限制 (普通對(duì)象)
存在即真理,對(duì)比才知知道優(yōu)劣
這邊只是用了簡(jiǎn)單的類型進(jìn)行限制,好像常規(guī)類型代碼量看起來(lái)比較少~
// 常規(guī)類型限制
function f1(obj: { label: string }) {
console.log("f => obj.label:", obj.label);
}
f1({ label: "string" });
// 接口類型限制
interface objType {
label: string;
}
function f2(obj: objType) {
console.log("f2 => obj.label:", obj.label);
}
f2({ label: "string" });
思考:如果類型比較復(fù)雜,并且其他函數(shù)也是有相同的類型約束,需要復(fù)用...孰優(yōu)孰劣呢~
// 常規(guī)類型限制
function consoleConfig(obj: { label1: string,label2:string,label3:string,label4:string}) {
console.log("f => obj:", obj);
}
function setConfig(obj: { label1: string,label2:string,label3:string,label4:string}) {
Window.config = obj;
}
這邊的參數(shù)還是有點(diǎn)少,怕代碼太多了…自行腦補(bǔ) ;)
這樣是不是就舒服多了
// 定義通用接口
interface Config{
label1: string;
label2: string;
label3: string;
label4: string;
}
// 使用接口
function consoleConfig2(obj: Config) {
console.log("f => obj:", obj);
}
function setConfig2(obj: Config) {
// do something...
}
2. 可選屬性
好處:可以對(duì)可能存在的屬性進(jìn)行預(yù)定義
interface objType3 {
label: string;
// 可選屬性
params?: string;
}
function f3(obj: objType3) {
console.log("f3 => obj.label:", obj.label);
if (obj.params) {
console.log("f3 => 可選參數(shù),存在才觸發(fā) obj.params:", obj.params);
}
}
// 可以打印label
f3({ label: "string" });
// 可以打印label,params是可選屬性,有的話也會(huì)執(zhí)行打印
f3({ label: "string", params: "test" });
3. 只讀屬性
const 用于變量
readonly 用于對(duì)象的屬性
只讀的類型限制是不能夠修改的,除非你用了斷言,告訴編譯器,我知道這個(gè)東西,我知道怎么用,斷言如下:
interface Point {
readonly x: number;
readonly y: number;
}
function f4(point: Point) {
// point.x=50; // 報(bào)錯(cuò),只讀對(duì)象不能修改
console.log(point);
console.log("f4 => point:", point);
}
f4({ x: 50, y: 50 });
// 使用斷言對(duì)只讀屬性進(jìn)行修改
let a: number[] = [1, 2, 3, 4];
// ReadonlyArray<T>類型
let ro: ReadonlyArray<number> = a;
// ro[0] = 1; // Error
// 使用類型斷言
a = ro as number[];
4. 額外的屬性
額外的屬性盡量少用,這個(gè)可能會(huì)讓TS檢測(cè)不出BUG,除非是調(diào)用者的一些自定義配置
interface config {
a?: string;
b?: string;
[propName: string]: any; // 跳過(guò)檢測(cè)
}
function f5(config: config) {
return config;
}
// 對(duì)象的屬性c 是跳過(guò)檢測(cè)的...
let config = f5({ a: "aaa", c: "ccc" });
5. 可索引的類型
TypeScript支持兩種索引簽名:字符串和數(shù)字。
// 數(shù)字索引 針對(duì)數(shù)組
interface numberArray {
[index: number]: string;
}
let nArr: numberArray = ["1", "2", "3"];
nArr = {
0: "1",
1: "2",
2: "3",
};
// 字符串索引 針對(duì)對(duì)象
// 因?yàn)樽址饕暶髁?obj.property和obj["property"]兩種形式都可以。
interface StringArray {
readonly [index: string]: string;
}
let sArr: StringArray;
// sArr[0]="0"; // Error 設(shè)置了readonly 后,只能對(duì)對(duì)象進(jìn)行賦值,不能通過(guò)下標(biāo)賦值~
// sArr= ["1", "2", "3"]; // Error 數(shù)組默認(rèn)是字符串下標(biāo),數(shù)組的是數(shù)值
sArr = {
"0": "1",
"1": "2",
"2": "3",
};
interface Shape {
color: string;
}
6. 函數(shù)類型 (函數(shù))
接口能夠描述JavaScript中對(duì)象擁有的各種各樣的外形。 除了描述帶有屬性的普通對(duì)象外,接口也可以描述函數(shù)類型。
// 該接口實(shí)現(xiàn)了函數(shù)類型的限制
interface tsFunc {
(str1: string, str2: string): string;
}
let myFunc: tsFunc = function (string1: string, string2: string) {
return string1 + string2;
};
console.log(myFunc("a", "b"));
// console.log(myFunc("a",1)); // Error 函數(shù)接口已經(jīng)做了限制
7. 類類型-實(shí)現(xiàn)implements (類)
類只要聲明了成員就一定要對(duì)其進(jìn)行初始化
1.初始化表達(dá)式
2.構(gòu)造函數(shù)中明確賦值。
這邊不對(duì)類進(jìn)行多余的講解,類將專門拿出一章節(jié)來(lái) ;)
- 嚴(yán)格意義上構(gòu)造函數(shù)不屬于成員,只是為了在實(shí)例化的時(shí)候初始化一些成員,不必劍走偏鋒,想要將構(gòu)造函數(shù)constructor 進(jìn)行限制~~~
- 類實(shí)現(xiàn)接口,所限制的只是類實(shí)現(xiàn)了接口的類型限制,就是類可以有自己的一些自定義的成員
如下方類Clock,接口是ClockInterface
- currentTime變量成員:接口有了,則類要有聲明,賦值可以用表達(dá)式
- setTime函數(shù)成員:接口有了,則類要有聲明,賦值可以在構(gòu)造函數(shù)
- getDay函數(shù)成員:接口中是可選屬性,則類中可有可無(wú)
- getDate函數(shù)函數(shù):接口中沒(méi)有,則類中可有可無(wú)
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
// 這邊也可以設(shè)置可選屬性~
getDay?(): number;
// 這里注釋了也沒(méi)問(wèn)題,因?yàn)轭悓?shí)現(xiàn)接口只需滿足 接口存在的類型限制
// 接口描述了類的部分類型限制
// getDate(): number;
}
class Clock implements ClockInterface {
// 當(dāng)前時(shí)間
// 初始化表達(dá)式賦值...
currentTime = new Date();
// 設(shè)置時(shí)間
setTime;
// 這邊是可選屬性,注釋了也沒(méi)問(wèn)題~
// getDay = () => {
// return this.currentTime.getDay();
// };
// 類中可以自定義成員,不需要被類類型的接口限制死
// 獲取當(dāng)前幾號(hào)
getDate = () => {
return this.currentTime.getDate();
};
constructor(h: number, m: number) {
// 在構(gòu)造函數(shù)中賦值...
this.setTime = (d: Date) => {
this.currentTime = d;
};
}
}
繼承
繼承,主要看你想要繼承到什么~
- 繼承接口
- 繼承類的成員以及實(shí)現(xiàn) (不在本章節(jié)~)
- 繼承類的所有成員類型限制
1. 接口繼承接口
接口的繼承也是用關(guān)鍵字extends
// 定義一個(gè) "形狀" 接口,附加顏色通用屬性
interface Shape {
color: string;
}
// 定義一個(gè) "正方形" 接口,他繼承了 "形狀" 接口,并且?guī)Я诉呴L(zhǎng)屬性
interface Square extends Shape {
sideLength: number;
}
// 調(diào)用方式1. 斷言1
// TypeScript 斷言 <Type>
// 通過(guò)類型斷言這種方式可以告訴編譯器,“相信我,我知道自己在干什么”。
// 類型斷言好比其他語(yǔ)言里的類型轉(zhuǎn)換,但是不進(jìn)行特殊的數(shù)據(jù)檢查和解構(gòu)。它沒(méi)有運(yùn)行時(shí)的影響,只是在編譯階段起作用。
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
// 調(diào)用方式1. 斷言2 as 語(yǔ)法
let square1 = {} as Square;
square1.color = "red";
square1.sideLength = 12;
// 在賦值前不能使用了變量“square2”。
let square2: Square;
// square2.color = "green"; // Error 在賦值前使用了變量“square1”
// square2.sideLength = 100; // Error 在賦值前使用了變量“square1”
2. 接口繼承類
接口繼承類也是用關(guān)鍵字extends
場(chǎng)景:已經(jīng)有現(xiàn)成的父類Father,父類的接口實(shí)現(xiàn)是FatherInterface文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-411688.html
// 先來(lái)初始化父類
// 父類接口 FatherInterface
interface FatherInterface {
// 只對(duì)name成員進(jìn)行了類型限制
name: string;
// 只對(duì)getName成員進(jìn)行了類型限制
getName(): string;
}
// 父類 已經(jīng)實(shí)現(xiàn)接口
class Father implements FatherInterface {
name;
getName = () => {
return "Father:" + this.name;
};
// 這邊添加了一個(gè)成員,跟FatherInterface區(qū)分開(kāi)
// 等下看看繼承Father的接口是否也繼承了sex的類型限制
sex;
constructor(name: string, sex: string) {
this.name = name;
this.sex = sex;
}
}
1 | 目標(biāo) | 方法 |
---|---|---|
2 | 想要繼承FatherInterface | 用接口繼承接口即可 |
3 | 想要繼承Father中的所有成員 | 用類繼承類 |
4 | 只要Fahter中的所有成員類型限制,所有的成員自己實(shí)現(xiàn) | 接口繼承類 |
// 針對(duì):只要Father中的所有成員類型限制,所有的成員自己賦值
// 繼承父類所有的類型,不止FatherInterface接口中的name,還有Father類中sex
// 這邊只是對(duì)接口進(jìn)行了繼承,不是對(duì)類進(jìn)行繼承,所以不會(huì)得到Father成員實(shí)現(xiàn),只有聲明~
// 所以需要重新實(shí)現(xiàn)
// 子類接口 Father1Interface 對(duì)age進(jìn)行了類型限制
interface Father1Interface extends Father {
age: number;
}
class Father1 implements Father1Interface {
// 只是繼承了類的類型限制,這邊需要重新聲明
name;
// 只是繼承了類的類型限制,這邊需要重新聲明
sex;
// 只是繼承了類的類型限制,需要對(duì)其進(jìn)行聲明并且實(shí)現(xiàn)
getName = () => {
return "Father1:" + this.name;
};
// 普通接口成員聲明
age;
constructor(name: string, sex: string, age: number) {
// 只是繼承了類的類型限制,這邊需要重新實(shí)現(xiàn)
this.name = name;
// 只是繼承了類的類型限制,這邊需要重新實(shí)現(xiàn)
this.sex = sex;
// 普通接口成員實(shí)現(xiàn)
this.age = age;
}
}
// new Father1 實(shí)例化一個(gè)對(duì)象,father1
let father1 = new Father1("另外的爸爸:", "男", 68);
console.log(
father1.getName()
);
這邊可以弄個(gè)類繼承類對(duì)比下
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-411688.html
class Children extends Father {
age: number;
constructor(name: string, sex: string, age: number) {
super(name, sex);
this.age = age;
}
}
let children = new Children("兒子", "男", 18);
console.log(
// 子類沒(méi)有重新實(shí)現(xiàn),則可以調(diào)用父類的getName()
children.getName()
);
源碼
/*
* @Author: Penk
* @LastEditors: Penk
* @LastEditTime: 2022-11-17 16:13:08
* @FilePath: \typescript-tutorial\03_interface-接口\index.ts
* @Desc: 接口interface主要用于對(duì)象變量,方便復(fù)用,以及對(duì)類進(jìn)行實(shí)現(xiàn)接口,以便實(shí)現(xiàn)成員類型限制
* @email: 492934056@qq.com
*/
// ----------------------常規(guī)類型限制---------------------- //
console.log("----------------------常規(guī)類型限制----------------------");
function f1(obj: { label: string }) {
console.log("f => obj.label:", obj.label);
}
f1({ label: "string" });
// ----------------------接口類型限制---------------------- //
console.log("----------------------接口類型限制----------------------");
interface objType {
label: string;
}
function f2(obj: objType) {
console.log("f2 => obj.label:", obj.label);
}
f2({ label: "string" });
// ----------------------常規(guī)類型限制 vs 接口類型限制---------------------- //
console.log(
"----------------------常規(guī)類型限制 vs 接口類型限制----------------------"
);
// 方法 consoleConfig setConfig 參數(shù)都一樣...
function consoleConfig(obj: {
label1: string;
label2: string;
label3: string;
label4: string;
}) {
console.log("f => obj:", obj);
}
function setConfig(obj: {
label1: string;
label2: string;
label3: string;
label4: string;
}) {
// do something...
}
// 定義通用接口,是不是看起來(lái)舒服一點(diǎn)了~~~
interface Config {
label1: string;
label2: string;
label3: string;
label4: string;
}
// 使用接口
function consoleConfig2(obj: Config) {
console.log("f => obj:", obj);
}
function setConfig2(obj: Config) {
// do something...
}
// ----------------------接口類型-可選屬性---------------------- //
// 好處:可以對(duì)可能存在的屬性進(jìn)行預(yù)定義
console.log("----------------------接口類型-可選屬性----------------------");
interface objType3 {
label: string;
// 可選屬性
params?: string;
}
function f3(obj: objType3) {
console.log("f3 => obj.label:", obj.label);
if (obj.params) {
console.log("f3 => 可選參數(shù),存在才觸發(fā) obj.params:", obj.params);
}
}
// 可以打印label
f3({ label: "string" });
// 可以打印label,params是可選屬性,有的話也會(huì)執(zhí)行打印
f3({ label: "string", params: "test" });
// ----------------------接口類型-只讀屬性---------------------- //
// const 用于變量
// readonly 用于對(duì)象的屬性
console.log("----------------------接口類型-只讀屬性----------------------");
interface Point {
readonly x: number;
readonly y: number;
}
function f4(point: Point) {
// point.x=50; // 報(bào)錯(cuò),只讀對(duì)象不能修改
console.log(point);
console.log("f4 => point:", point);
}
f4({ x: 50, y: 50 });
// 使用斷言對(duì)只讀屬性進(jìn)行修改
let a: number[] = [1, 2, 3, 4];
// ReadonlyArray<T>類型
let ro: ReadonlyArray<number> = a;
// ro[0] = 1; // Error
// 使用類型斷言
a = ro as number[];
// ----------------------接口類型-額外的屬性---------------------- //
// 額外的屬性盡量少用,這個(gè)可能會(huì)讓TS檢測(cè)不出BUG,除非是調(diào)用者的一些自定義配置
console.log("----------------------接口類型-額外的屬性----------------------");
interface config {
a?: string;
b?: string;
[propName: string]: any; // 跳過(guò)檢測(cè)
}
function f5(config: config) {
return config;
}
// 對(duì)象的屬性c 是跳過(guò)檢測(cè)的...
let config = f5({ a: "aaa", c: "ccc" });
// ----------------------接口類型-可索引的類型---------------------- //
// TypeScript支持兩種索引簽名:字符串和數(shù)字。
console.log("----------------------接口類型-可索引的類型--------------------");
// 數(shù)字索引 針對(duì)數(shù)組
interface numberArray {
[index: number]: string;
}
let nArr: numberArray = ["1", "2", "3"];
nArr = {
0: "1",
1: "2",
2: "3",
};
// 字符串索引 針對(duì)對(duì)象
// 因?yàn)樽址饕暶髁?obj.property和obj["property"]兩種形式都可以。
interface StringArray {
readonly [index: string]: string;
}
let sArr: StringArray;
// sArr[0]="0"; // Error 設(shè)置了readonly 后,只能對(duì)對(duì)象進(jìn)行賦值,不能通過(guò)下標(biāo)賦值~
// sArr= ["1", "2", "3"]; // Error 數(shù)組默認(rèn)是字符串下標(biāo),數(shù)組的是數(shù)值
sArr = {
"0": "1",
"1": "2",
"2": "3",
};
// ----------------------接口類型-函數(shù)類型---------------------- //
// 接口能夠描述JavaScript中對(duì)象擁有的各種各樣的外形。 除了描述帶有屬性的普通對(duì)象外,接口也可以描述函數(shù)類型。
console.log("----------------------接口類型-函數(shù)類型----------------------");
interface tsFunc {
(str1: string, str2: string): string;
}
let myFunc: tsFunc = function (string1: string, string2: string) {
return string1 + string2;
};
console.log(myFunc("a", "b"));
// console.log(myFunc("a",1)); // Error 函數(shù)接口已經(jīng)做了限制
// ----------------------類類型-實(shí)現(xiàn)接口---------------------- //
// 嚴(yán)格意義上構(gòu)造函數(shù)不屬于成員,只是為了在實(shí)例化的時(shí)候初始化一些成員,不必劍走偏鋒,想要將構(gòu)造函數(shù)constructor 進(jìn)行限制~~~
// 類實(shí)現(xiàn)接口,所限制的只是類實(shí)現(xiàn)了接口的類型限制,就是類可以有自己的一些自定義的成員
// 如下方類Clock,接口是ClockInterface
// 1. currentTime變量成員:接口有了,則類要有聲明,賦值可以用表達(dá)式
// 2. setTime函數(shù)成員:接口有了,則類要有聲明,賦值可以在構(gòu)造函數(shù)
// 3. getDay函數(shù)成員:接口中是可選屬性,則類中可有可無(wú)
// 4. getDate函數(shù)函數(shù):接口中沒(méi)有,則類中可有可無(wú)
console.log("----------------------類類型-實(shí)現(xiàn)implements--------------------");
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
// 這邊也可以設(shè)置可選屬性~
getDay?(): number;
// 這里注釋了也沒(méi)問(wèn)題,因?yàn)轭悓?shí)現(xiàn)接口只需滿足 接口存在的類型限制
// 接口描述了類的部分類型限制
// getDate(): number;
}
class Clock implements ClockInterface {
// 當(dāng)前時(shí)間
// 初始化表達(dá)式賦值...
currentTime = new Date();
// 設(shè)置時(shí)間
setTime;
// 這邊是可選屬性,注釋了也沒(méi)問(wèn)題~
// getDay = () => {
// return this.currentTime.getDay();
// };
// 類中可以自定義成員,不需要被類類型的接口限制死
// 獲取當(dāng)前幾號(hào)
getDate = () => {
return this.currentTime.getDate();
};
constructor(h: number, m: number) {
// 在構(gòu)造函數(shù)中賦值...
this.setTime = (d: Date) => {
this.currentTime = d;
};
}
}
// ----------------------繼承接口---------------------- //
// 接口的繼承也是用關(guān)鍵字extends
console.log("----------------------繼承接口--------------------");
// 定義一個(gè) "形狀" 接口,附加顏色通用屬性
interface Shape {
color: string;
}
// 定義一個(gè) "正方形" 接口,他繼承了 "形狀" 接口,并且?guī)Я诉呴L(zhǎng)屬性
interface Square extends Shape {
sideLength: number;
}
// 調(diào)用方式1. 斷言1
// TypeScript 斷言 <Type>
// 通過(guò)類型斷言這種方式可以告訴編譯器,“相信我,我知道自己在干什么”。
// 類型斷言好比其他語(yǔ)言里的類型轉(zhuǎn)換,但是不進(jìn)行特殊的數(shù)據(jù)檢查和解構(gòu)。它沒(méi)有運(yùn)行時(shí)的影響,只是在編譯階段起作用。
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
// 調(diào)用方式1. 斷言2 as 語(yǔ)法
let square1 = {} as Square;
square1.color = "red";
square1.sideLength = 12;
// 在賦值前不能使用了變量“square2”。
let square2: Square;
// square2.color = "green"; // Error 在賦值前使用了變量“square1”
// square2.sideLength = 100; // Error 在賦值前使用了變量“square1”
// ----------------------類類型-接口繼承類---------------------- //
// 具體的class將會(huì)專門做一篇文章~~~
// 接口繼承類也是用關(guān)鍵字extends
// 場(chǎng)景:已經(jīng)有現(xiàn)成的父類Father,父類的接口實(shí)現(xiàn)是FatherInterface
// 思考1:如果只是想單純繼承FatherInterface 就是上一節(jié)的內(nèi)容。
// 思考2:如果想要繼承Father里面所有的屬性呢?FatherInterface只是對(duì)父類的部分成員進(jìn)行了類型限制?。?!
// console.log("--------------------類類型-接口繼承類--------------------");
// 先來(lái)初始化父類
// 父類接口 FatherInterface
interface FatherInterface {
// 只對(duì)name成員進(jìn)行了類型限制
name: string;
getName(): string;
}
// 父類 已經(jīng)實(shí)現(xiàn)接口
class Father implements FatherInterface {
name;
getName = () => {
return "Father:" + this.name;
};
// 這邊添加了一個(gè)成員,跟FatherInterface區(qū)分開(kāi)
// 等下看看繼承Father的接口是否也繼承了sex的類型限制
sex;
constructor(name: string, sex: string) {
this.name = name;
this.sex = sex;
}
}
// 想要繼承FatherInterface | 用接口繼承接口即可
// 想要繼承Father中的所有成員 | 用類繼承類
// 只要Fahter中的所有成員類型限制,所有的成員自己賦值| 接口繼承類
// 針對(duì):只要Father中的所有成員類型限制,所有的成員自己賦值
// 繼承父類所有的類型,不止FatherInterface接口中的name,還有Father類中sex
// 這邊只是對(duì)接口進(jìn)行了繼承,不是對(duì)類進(jìn)行繼承,所以不會(huì)得到Father成員實(shí)現(xiàn),只有聲明~
// 所以需要重新實(shí)現(xiàn)
// 子類接口 Father1Interface 對(duì)age進(jìn)行了類型限制
interface Father1Interface extends Father {
age: number;
}
class Father1 implements Father1Interface {
// 只是繼承了類的類型限制,這邊需要重新聲明
name;
// 只是繼承了類的類型限制,這邊需要重新聲明
sex;
// 只是繼承了類的類型限制,需要對(duì)其進(jìn)行聲明并且實(shí)現(xiàn)
getName = () => {
return "Father1:" + this.name;
};
// 普通接口成員聲明
age;
constructor(name: string, sex: string, age: number) {
// 只是繼承了類的類型限制,這邊需要重新實(shí)現(xiàn)
this.name = name;
// 只是繼承了類的類型限制,這邊需要重新實(shí)現(xiàn)
this.sex = sex;
// 普通接口成員實(shí)現(xiàn)
this.age = age;
}
}
// new Father1 實(shí)例化一個(gè)對(duì)象,father1
let father1 = new Father1("另外的爸爸:", "男", 68);
console.log(
father1.getName()
);
// 這邊可以弄個(gè)類繼承類對(duì)比下
class Children extends Father {
age: number;
constructor(name: string, sex: string, age: number) {
super(name, sex);
this.age = age;
}
}
let children = new Children("兒子", "男", 18);
console.log(
// 子類沒(méi)有重新實(shí)現(xiàn),則可以調(diào)用父類的getName()
children.getName()
);
到了這里,關(guān)于TypeScript--接口interface的定義,實(shí)現(xiàn),繼承的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!