工具: PlayGround
接口
接口用來定義對象的結構和類型,描述對象應該具有哪些屬性和方法。
它僅用于聲明,而不是實現; 這對于編寫可重用的代碼非常有用。它可用于:
關鍵字是interface
, 注意:它只是作為TypeScript
的一部分,并不會轉換為JavaScript
- 數組定義
interface data {[index:number]: number,
}// 類型一致,沒有問題
let numList_1: data = [1, 2, 3];
// Type 'string' is not assignable to type 'number'
let numList_2: data = [1, "", 3];
- 對象的定義
// 方式1
interface Data_1 {name: string,age: number,
}
let data_1: Data_1 = {name: "hello",age: 20,
}
console.log(data_1);// 方式2
interface Data_2 {name: string;age: number;// 可選屬性, 表示可以選擇不賦值sex?: number;// 只讀屬性,表示一旦賦值后不可修改 readonly id:number | string;
}
let data_2: Data_2 = {name: "hello",age: 20,id : "0001",
}
data_2.age = 10;
// Error: Cannot assign to 'id' because it is a read-only property
data_2.id = 10;
- 作為類實現
interface Person {name: string;age: number;greet: () => void;
}// 通過implements實現接口
class Student implements Person {name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}greet() {console.log(`Hello, my name is ${this.name}`);}
}let student = new Student("ok", 20);
student.greet(); // "Hello, my name is ok"
類
typeScript中類的使用,主要通過class
來創建類對象,通過new
來實例化類對象, 支持特性:
-
instanceof
檢測對象類型 -
訪問權限
public
、protected
和private
-
函數重載
-
繼承或重寫
-
靜態成員和方法
基本的使用:
class Demo {private _name: string = "";private _age: number = 0;// 構造函數constructor(name:string) {this._name = name;} public log() {console.log(`Demo 的名字為${this._name}`);}
}
let demo = new Demo("demo");
console.log(typeof(demo)); // "object"
console.log(demo instanceof Demo); // true
函數重載
類的函數重載的編寫方式,不要直接實現:
class Demo {private _name: string = "";private _age: number = 0;// 構造函數constructor(name:string) {//} // Error: Multiple constructor implementations are not allowed// 原因在于如果實現,編譯器創建對象不知道調用哪個構造函數constructor(name: string, age:number) {//}
}
可以通過采用聲明和可選參數的方式來實現:
// 實例1
class Demo {private _name: string = "";private _age: number = 0;// 構造函數constructor(name:string);constructor(name: string, age:number);constructor(name: string, age?:number) {this._name = name;if (age) {this._age = age;}}
}// 實例2:
class Calculator {add(a: number, b: number): number;add(a: string, b: string): string;add(a: any, b: any): any {if (typeof a === 'number' && typeof b === 'number') {return a + b;} else if (typeof a === 'string' && typeof b === 'string') {return a.concat(b);} else {throw new Error('Invalid arguments');}}
}const calculator = new Calculator();console.log(calculator.add(1, 2)); // 3
console.log(calculator.add('Hello', ' World')); // Hello World
繼承和重寫
繼承的話,使用extends
, 如果對基類中的方法重新編寫,就是重寫
// 定義接口,簡單的實例可以忽略;增加的話,有助于理解代碼和重寫代碼相關
interface Animal {sound(): void;
}// 實現接口
class Cat implements Animal {private _breed: string;private _name: string = "Cat";constructor(breed: string) {this._breed = breed;}// 通過get和set的方式設置對象變量屬性get Name():string {return this._name;}set Name(name: string) {this._name = name;}sound(): void {console.log("貓");}
}// 繼承
class DomesticCat extends Cat {public log() {console.log("this is DomesticCat");}
}// 重寫
class WildCat extends DomesticCat {sound(): void {console.log("野貓叫聲");}
}const domesticCat = new DomesticCat("domesticCat");
domesticCat.Name = "短毛貓"
console.log(`cat Name: ${domesticCat.Name}`); //"cat Name: 短毛貓"
domesticCat.sound(); // 貓//
const wildCat = new WildCat("豹貓");
wildCat.sound(); // 野貓叫聲
注意:
- 如果未聲明訪問權限
public
、protected
和private
,則默認為public
- 對于變量,建議開頭增加下劃線
_
表示私有 - 可以多繼承,只需要在
extends
后面添加類接口即可 - 注意區分
implements
和extends
,前者主要用于對interface聲明的方法等進行實現, 而后者主要應用于已經實現后的方法進行繼承或重寫。
Static
靜態變量或方法在類中聲明后,可以不通過new
對象直接賦值或使用,但賦值后不可在改變。
class Demo {static value: number;static getValue() {console.log(`static value: ${Demo.value}`);}
}
Demo.value = 10;
Demo.getValue(); //"static value: 10"
它常用于編寫單例模式,注意: 構造函數設置為私有,以保證對象的唯一性
class Singleton {private static instance: Singleton;private constructor() {// 私有化構造函數,防止外部實例化}public static getInstance(): Singleton {if (!Singleton.instance) {Singleton.instance = new Singleton();}return Singleton.instance;}public greet(): void {console.log("Hello");}
}// 創建單例實例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();console.log(instance1 === instance2); // trueinstance1.greet(); // "Hello"
instance2.greet(); // "Hello"
const
作為常量使用,在類中使用注意:
- 只能用于修改基本數據類型和對象屬性字面量,不可用于修飾引用類型
- 如果聲明
const
一定要記得初始化,不能在構造函數或其他函數進行初始化 - 聲明以后,其本質就是
readonly
只讀屬性
class MyClass {readonly PI: number = 3.14;readonly config: { name: string, age: number } = { name: "John", age: 25 };constructor() {// this.PI = 3.14159; // 錯誤,無法對只讀屬性進行重新賦值// this.config = { name: "Alice", age: 30 }; // 錯誤,無法對只讀屬性進行重新賦值this.config.name = "Alice"; // 正確,可以修改對象字面量屬性的值this.config.age = 30; // 正確,可以修改對象字面量屬性的值}printInfo(): void {console.log(`PI: ${this.PI}`);console.log(`Name: ${this.config.name}, Age: ${this.config.age}`);}
}const myObj = new MyClass();
myObj.printInfo();// "PI: 3.14"
// "Name: Alice, Age: 30"