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,期待再相見!