Implement the built-in
Readonly<T>
generic without using it.
Constructs a type with all properties of T set to readonly, meaning the properties of the constructed type cannot be reassigned.
實現內建的 Readonly<T>
泛型,而不使用它。
構造一個將 T 的所有屬性設為 readonly 的型別,意味著構造後的型別屬性無法被重新賦值。
interface Todo {
title: string
description: string
}
const todo: MyReadonly<Todo> = {
title: "Hey",
description: "foobar"
}
todo.title = "Hello" // Error: cannot reassign a readonly property
todo.description = "barFoo" // Error: cannot reassign a readonly property
接下來,你的任務是讓下面的type cases測試通過:
type cases = [
Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>,
]
interface Todo1 {
title: string
description: string
completed: boolean
meta: {
author: string
}
}
在這一關中,我們可以從以下幾個方向來思考:
MyReadonly
。T
的所有屬性都設置為 readonly
,確保屬性在初始化後不能被修改,從而達到不可變的效果。我們將會用到:
readonly
關鍵字。Mapped Types 在第三關已經介紹過,可以回到第三關參考喔!
實現 MyReadonly<T>
的關鍵在於使用 TypeScript 的mapped types語法來遍歷 T 的所有屬性並將其設為只讀 readonly
type MyReadonly<T> = {
readonly [P in keyof T] : T[P]
}
細節分析:
type MyReadonly<T> = { ... }
: 這定義了一個泛型類型 MyReadonly
,它接受一個類型 T
,並產生一個新的類型。在這個新的類型中,T
的所有屬性都被設為只讀。
readonly [P in keyof T]
: 這部分使用 TypeScript 的映射類型語法遍歷 T
的所有鍵(屬性名稱)P
。這裡的 keyof T
會獲得 T
所有屬性的聯合類型(例如,如果 T
包含屬性 a
和 b
,keyof T
會是 'a' | 'b'
)。
[P in keyof T]
: 這是 TypeScript 的索引簽名(index signature)的一種用法,表示對 T
中的每個屬性鍵 P
執行操作。在這裡,它的目的是遍歷 T
中的每個屬性鍵,並對它們進行只讀處理。readonly
: 這個關鍵字使得映射出的每個屬性都變成只讀屬性。這意味著一旦對這個類型的物件進行了初始化,就不能再改變這些屬性的值。例如,如果你有一個物件 obj
,你不能對 obj
的 property
屬性進行賦值操作。
T[P]
: 這表示對於每個鍵 P
,我們保留 T
中對應屬性的原始類型。也就是說,MyReadonly
類型中的每個屬性的型別和原來 T
中的一樣,只不過現在這些屬性是只讀的。例如,若 T
中有一個屬性 a
,它的型別是 string
,那麼 MyReadonly<T>
中 a
的型別也會是 string
,但它是只讀的。
這樣,我們就能順利通過測試啦 🎉 😭 🎉
Readonly<Type>
(TypeScript 內建 Utility Type):
interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: "Delete inactive users",
};
todo.title = "Hello"; // Cannot assign to 'title' because it is a read-only property.
Mapping Modifiers(修飾符):
readonly
和 ?
。你可以通過在修飾符前加上 -
或 +
來添加或移除這些修飾符。如果你沒有加上 prefix (前綴),則默認假設是 +
。// Removes 'readonly' attributes from a type's properties
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property];
};
type LockedAccount = {
readonly id: string;
readonly name: string;
};
type UnlockedAccount = CreateMutable<LockedAccount>;
//^? type UnlockedAccount = {
// id: string;
// name: string;
// }
// Removes 'optional' attributes from a type's properties
type Concrete<Type> = {
[Property in keyof Type]-?: Type[Property];
};
type MaybeUser = {
id: string;
name?: string;
age?: number;
};
type User = Concrete<MaybeUser>;
//^? type User = {
// id: string;
// name: string;
// age: number;
// }
本次介紹了 Readonly
的實作,下一關會挑戰Tuple to Object
,期待再相見!