簡言
在 JavaScript 中,我們分組和傳遞數據的基本方式是通過對象。在 TypeScript 中,我們通過對象類型來表示這些對象。
對象類型
在 JavaScript 中,我們分組和傳遞數據的基本方式是通過對象。在 TypeScript 中,我們通過對象類型來表示這些對象。
正如我們所看到的,它們可以是匿名的:
function greet(person: { name: string; age: number }) {return "Hello " + person.name;
}
或使用接口來命名:
interface Person {name: string;age: number;
}function greet(person: Person) {return "Hello " + person.name;
}
又或者使用別名:
type Person = {name: string;age: number;
};function greet(person: Person) {return "Hello " + person.name;
}
這三種方式都挺常見的,一般都是使用后兩種,使用接口或別名來定義類型,簡單明了,且易復用。
對象屬性類型
對象類型中的每個屬性都可以指定幾件事:類型、屬性是否可選以及屬性是否可以寫入,以及屬性值。
定義規則如下:
- 屬性類型 – 一般是字符串類型的,如果想定義其他的類型,用方括號包裹定義屬性索引修改。
- 屬性值 – 和普通的變量類型定義一樣,如果提前定義好了屬性值,則需要符合提前定義好的類型范圍。
- 可選屬性 — 問號(?)定義。
- 僅讀屬性 — 屬性默認是可寫入的,僅讀屬性需要 索引前面加 readonly 關鍵詞。
示例:
interface Person {name: string;age: number;
}
type Shape = { kind: "circle" } | { kind: "square" };
interface PaintOptions {shape: Shape;xPos?: number;yPos?: number;
}interface ReadonlyPerson {readonly name: string;readonly age: number;
}let writablePerson: Person = {name: "Person McPersonface",age: 42,
};// works
let readonlyPerson: ReadonlyPerson = writablePerson;console.log(readonlyPerson.age); // prints '42'
writablePerson.age++;
console.log(readonlyPerson.age); // prints '43'interface StringArray {[index: number]: string;
}const myArray: StringArray = ['1','2'];
const secondItem = myArray[1];
對象索引類型
使用方括號包含索引index屬性定義。
interface NumberOrStringDictionary {[index: string]: number | string;length: number; // ok, length is a numbername: string; // ok, name is a string
}
上面提前定義了屬性索引類型和屬性值類型,不好擴展,也可以不指定屬性值,即將屬性值定義為any(任何類型):
interface SquareConfig {[index: string]: any;color?: string;width?: number;
}
可以在索引屬性前加readonly,這樣屬性值不可修改:
interface ReadonlyStringArray {readonly [index: number]: string;
}let myArray: ReadonlyStringArray = getReadOnlyStringArray();
myArray[2] = "Mallory"; // 報錯
接口繼承
使用接口定義的對象類型,可以使用關鍵詞extends來繼承其他接口。
interface Colorful {color: string;
}interface Circle {radius: number;
}interface ColorfulCircle extends Colorful, Circle {}const cc: ColorfulCircle = {color: "red",radius: 42,
};
類型組合
接口允許我們通過擴展其他類型來創建新類型。TypeScript 提供了另一種稱為交叉類型的結構,主要用于組合現有的對象類型。
組合類型是使用 & 運算符定義的。
interface Colorful {color: string;
}
interface Circle {radius: number;
}type ColorfulCircle = Colorful & Circle;type c1 = Colorful
type c2 = Circletype c3 = c1 & c2 // Colorful & Circle
類似于數學中的并集運算。
泛型對象類型
可以使用泛型,來定義通用的對象類型。
interface Box<Type> {contents: Type;
}
// 別名也可以使用泛型
type OrNull<Type> = Type | null;type OneOrMany<Type> = Type | Type[];type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>;
使用時,指定Type具體的類型值,其contents屬性即可動態改變。
let box: Box<string>;
將 Box 視為真實類型的模板,其中 Type 是一個占位符,將被其他類型替換。當 TypeScript 看到 Box<string> 時,它會用 string 替換 Box<Type> 中 Type 的每一個實例,并最終使用 { contents: string } 這樣的代碼。
元組對象類型
元組有的時候在表示列表對象類型時特別適合。
function doSomething(stringHash: [string, number]) {const [inputString, hash] = stringHash;console.log(inputString);console.log(hash);
}
元組也可以使用剩余元素,但必須是數組/元組類型。
type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];
為什么可選元素和剩余元素會有用?因為它允許 TypeScript 將元組與參數列表對應起來。元組類型可用于其余參數和參數,因此:
function readButtonInput(...args: [string, number, ...boolean[]]) {const [name, version, ...input] = args;// ...
}
// 相當于
function readButtonInput2(name: string, version: number, ...input: boolean[]) {// ...
}
結語
結束了。