@
基礎知識
建立型別
class Abc { }
類的初始化
const abc = new Abc();
型別和值
類既可以作為型別使用,也可以作為值使用。
const a:Bag = new Bag()
JSDoc 註釋
JSDoc 是 JavaScript 的一種註釋規範,它使用特定的註釋格式來自動生成 API 文件。JSDoc 透過註釋來提取資訊,例如函式名、引數型別和返回型別等,然後使用這些資訊生成人類可讀的文件。
示例:
/**
* 這是一個函式註釋
* @param {string} 引數名 - 引數描述
* @returns {number} 返回值描述
*/
function myFunction(引數名) {
// 函式實現
return 0;
}
在這個例子中,/** 開始一個多行註釋,然後在註釋中使用 @param 和 @returns 來描述函式的引數和返回值。JSDoc 還支援其他註釋標籤,例如 @description、@type 和 @example 等。
欄位
class User extends Account implements Updatable, Serializable {
id: string; //普通欄位
displayName?: boolean; //可選欄位
name!: string; //非可選欄位
#attributes: Map<any, any>; //私有欄位
roles = ["user"]; //有預設值的欄位
readonly createdAt = new Date() // 帶有預設值的只讀欄位
}
私有欄位
class Foo {
private myAny = 1;
}
class Bar {
#myAny = 1;
}
私有成員只能在它們所屬的類內部訪問,類的外部無法直接訪問這些私有成員。
示例:
class MyClass {
#myPrivateVariable: string;
public myPublicMethod() {
console.log(this.#myPrivateVariable); // 正確,可以在類內部訪問私有成員
}
}
const obj = new MyClass();
console.log(obj.#myPrivateVariable); // 錯誤,私有成員無法從外部訪問
區別
private在編譯後JavaScript中沒有影響,僅對TypeScript編譯器有影響,而使用#符號宣告的私有屬性在JavaScript中會被編譯為常規的私有屬性。
可選和非可選欄位
感嘆號(!)用於標記屬性或方法為非可選(non-optional)。這意味著該屬性或方法在類例項化時必須提供值,否則將導致編譯錯誤。
class Person {
constructor(public name: string, public age: number!) {
}
}
const person = new Person("Alice", 25); // 正確,age 屬性必須提供值
const personOptional = new Person("Bob"); // 錯誤,age 屬性未提供值
問號(?)用於標記屬性或方法為可選(optional)。這意味著該屬性或方法在類例項化時可以省略,不會導致編譯錯誤。
class Person {
constructor(public name: string, public age?: number) {
}
}
const person = new Person("Alice"); // 正確,age 屬性未提供值
const personOptional = new Person("Bob", 25); // 正確,age 屬性提供了值
欄位型別約束
[key: string]: number;
是一種物件型別的寫法,表示物件的鍵是字串型別,值是數字型別。
示例:
const person: { [key: string]: number } = {
age: 25,
height: 170,
weight: 65
};
Getter/Setter
Getter 是一個獲取屬性的方法,Setter 是一個設定屬性的方法。可以使用 get 和 set 關鍵字來定義它們。
Getter/Setter可以在不改變屬性的訪問許可權的情況下,對屬性的值進行更精細的控制。比如可以在讀取或設定屬性的值時新增額外的邏輯。
class Person {
private _name: string;
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
}
let person = new Person();
person.name = "John"; // 使用 setter 設定值
console.log(person.name); // 使用 getter 獲取值,輸出 "John"
靜態成員
靜態方法中this指向類本身,而不是類的例項物件。
class StaticClass {
n?:number=4;
//靜態欄位
static s:number
//靜態方法
static staticMethod() {
this.s=5
console.log('This is a static method');
}
}
StaticClass.staticMethod(); // 呼叫靜態方法
var staticClass=new StaticClass();
console.log(staticClass.n) //類成員不受影響 ,輸出4
console.log(staticClass.s) //undefined
console.log(StaticClass.n) //undefined
console.log(StaticClass.s) //靜態類成員不受影響 ,輸出5
函式過載
在 TypeScript 中,可以使用函式過載(Function Overloading)來定義多個同名函式,它們具有不同的引數型別或引數數量。這可以幫助提高程式碼的可讀性和可用性。
要實現函式過載,需要遵循以下規則:
- 過載的函式必須同名。
- 過載的函式引數型別或數量必須不同。
- 過載的函式可以有一個或多個過載。
- 函式過載不能改變函式的返回型別。
示例:
update: (retryTimes: number) => void;
update(retryTimes: number): void;
建構函式
建構函式是用於建立和初始化物件例項時候被呼叫的特殊方法,用於初始化物件的屬性併為其分配記憶體空間。
示例:
class Person {
private name: string;
private age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
console.log(`名字 ${this.name} 年齡 ${this.age}`);
}
}
var person = new Person("John", 30);
person.greet(); // 輸出 "名字 John 年齡 30"
引數屬性
可以使用引數屬性(Parameter Properties)來在類中定義與函式引數相關的屬性。引數屬性提供了一種簡潔的方式來宣告與函式引數相關的屬性,而不需要顯式地使用 this 關鍵字。
示例:
class Person {
constructor(public name: string, public age: number) {}
}
var person = new Person("John", 30);
console.log(person.name); // 輸出 "John"
console.log(person.age); // 輸出 30
類的例項化
(): JSONResponse // 可以透過 () 呼叫這個物件 -(JS中的函式是可以呼叫的物件)
new(s: string): JSONResponse; // 可以在此類物件上使用 new
示例:例項化泛型物件
class Person {
age= 25;
height= 170;
weight= 65;
constructor() {
}
}
class PersonService<TService> {
Service?: TService;
Init(service?: { new(): TService }) {
if (service != null) {
this.Service = new service();
}
}
}
var p = new PersonService<Person>();
p.Init(Person);
console.log(p.Service?.age); // 25
console.log(p.Service?.height); // 170
console.log(p.Service?.weight); // 65
箭頭函式
在箭頭函式中,this不指向呼叫該函式的物件,而是指向定義該箭頭函式時的上下文。
儘管箭頭函式是在物件的方法中定義的,但是它不會捕獲到呼叫該方法的物件作為自己的this上下文。
示例:
let obj = {
value: "I am an object",
printValue: () => { console.log(this.value); }
}
obj.printValue(); // 輸出:"I am an object"
this的作用域
全域性
在全域性作用域或單獨的函式作用域中,this引用的是全域性物件。
console.log(this); // 在全域性作用域中輸出:window物件
function testFunc() {
console.log(this); // 在函式作用域中輸出:window物件
}
testFunc();
類和物件方法
當函式作為物件的方法被呼叫時,this指的是obj物件。
let obj = {
name: 'Example Object',
printName: function() {
console.log(this.name);
}
}
obj.printName(); // 輸出:"Example Object"
當呼叫類中的函式時,this指的是類的例項物件。
class MyClass {
myMethod() {
console.log(this); // 輸出:MyClass的例項物件
}
}
const obj = new MyClass();
obj.myMethod();
泛型
泛型是一種允許你在定義類、介面、函式和方法時使用型別引數的功能。泛型允許你編寫靈活的程式碼,同時保持型別安全。透過使用泛型,你可以在強型別環境中編寫可重用的程式碼,而無需擔心具體的型別實現細節。
泛型類
class Box<Type>{
contents?: Type
constructor(value: Type) {
this.contents = value;
}}
var stringBox = new Box("a package");
console.log(stringBox.contents) // a package
泛型介面
interface Generator<T> {
generate(): T;
}
class RandomNumberGenerator implements Generator<number> {
generate() {
return Math.random();
}
}
let generator = new RandomNumberGenerator();
let randomNumber = generator.generate(); // 型別為 number
泛型函式
function identity<T>(arg: T): T {
return arg;
}
let x = identity<number>(123); // 型別為 number
let y = identity<string>("hello"); // 型別為 string
裝飾器
裝飾器是使用 @ 符號來標識的特殊型別的函式,可以用來擴充套件類或方法的行為。實現類似面向切面程式設計的特性。
可以在類、類方法、訪問器、屬性和方法引數上使用裝飾器
示例:
function log(target: any, obj:any) {
console.log(target)
console.log(`Creating instance of ${target.name}`);
}
@log
class MyClass {
myMethod() {
console.log("Hello, World!");
}
}
const instance = new MyClass();
TypeScript示例可在https://www.typescriptlang.org/play中除錯