[TS手冊學習] 04_對象類型
TS官方手冊:TypeScript: Handbook - The TypeScript Handbook (typescriptlang.org)
匿名與具名
對象類型的聲明可以是匿名的,也可以使用interface或type進行具名聲明。
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;
}
可選屬性 optional
使用?標記:
interface PaintOptions {
shape: Shape;
xPos?: number;
yPos?: number;
}
注:使用PaintOptions聲明的對象,它的xPos屬性會被初步推斷為number | undefined類型。
可以使用條件語句或者解構+默認值的方式收束類型,排除undefined的情況:
function paintShape(opts: PaintOptions) {
let xPos = opts.xPos === undefined ? 0 : opts.xPos;
// xPos 的類型為number
}
function paintShape({ shape, xPos = 0, yPos = 0 }: PaintOptions) {
// xPos 的類型為number,因為undefined會被默認值0取代
console.log("x coordinate at", xPos);
}
只讀屬性 readonly
interface SomeType {
readonly prop: string;
}
注:如果有一個屬性的值是引用值,例如一個對象或數組,且這個屬性被標記為只讀(readonly),我們不能修改它的引用值,但是可以修改它的內部屬性。
interface Home {
readonly resident: { name: string; age: number };
}
function visitForBirthday(home: Home) {
// 我們可以讀取并且更新'home.resident'里的屬性
console.log(`Happy birthday ${home.resident.name}!`);
home.resident.age++;
}
function evict(home: Home) {
// 但我們不能更新'home.resident'本身
home.resident = {
Cannot assign to 'resident' because it is a read-only property.
name: "Victor the Evictor",
age: 42,
};
}
索引簽名 index signatures
interface StringArray {
[index: number]: string;
}
const myArray: StringArray = getStringArray();
const secondItem = myArray[1];
索引的類型只能是:string,number,symbol,以及與這些類型相關的聯合類型。
通常只會考慮string和number類型的索引。
注:可以同時支持string,number兩種類型的索引器,但數字索引器返回的類型必須是字符串索引器返回類型的子類型。這是因為當使用數字進行索引時,JS 實際上會在索引到對象之前將其轉換為字符串。于是使用100和"100"進行索引的結果是一樣的。
當指定string類型索引的類型為S后,所有屬性的類型都需要是S的子集。
interface NumberDictionary {
[index: string]: number;
length: number; // ok
name: string; // NOT ok
}
這是因為當我們訪問obj.a的時候,其實也是在訪問obj["a"]。
在上面這個例子中,string類型索引被聲明為number類型,這意味著這個對象的所有屬性都是number類型,而下方name卻被聲明為string類型,矛盾了。
可以使用聯合類型解決這個問題:
interface NumberDictionary {
[index: string]: number | string;
length: number; // ok
name: string; // ok
}
同時,索引簽名也可以設置為只讀:
interface ReadonlyStringArray {
readonly [index: number]: string;
}
類型繼承
使用extends,支持多繼承:
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
interface ColorfulCircle extends Colorful, Circle {}
const cc: ColorfulCircle = {
color: "red",
radius: 42,
};
交集類型 intersection types
使用&運算符獲取已知的兩個類型的交集。
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
type ColorfulCircle = Colorful & Circle;
將兩個基本數據類型取交集會得到never。
類型繼承 VS 交集類型
二者都可以產生更復雜的類型。
前者是在原有的類型的基礎上添加可能未有的屬性形成新屬性,而后者將已有的類型進行組合。
泛型對象類型 Generic Object Types
interface Box<Type> {
contents: Type;
}
let box: Box<string>;
也可以與泛型函數結合使用:
function setContents<Type>(box: Box<Type>, newContents: Type) {
box.contents = newContents;
}
除了使用interface,也可以使用type別名定義泛型類型。interface一般用來聲明對象類型,而type更靈活,可以組合多種類型:
type OrNull<Type> = Type | null;
type OneOrMany<Type> = Type | Type[];
// type OneOrManyOrNull<Type> = OneOrMany<Type> | null
type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>;
// type OneOrManyOrNullStrings = OneOrMany<string> | null
type OneOrManyOrNullStrings = OneOrManyOrNull<string>;

浙公網安備 33010602011771號