# [TypeScript] Advent Of TypeScript 05 ###### tags `TypeScript` `Aot2023` <div style="display: flex; justify-content: flex-end"> > created: 2023/12/17 </div> ## 題目連結 [Day Five](https://typehero.dev/challenge/day-5) ```typescript= type SantasList = unknown; ``` ```typescript= const bads = ['tommy', 'trash'] as const; const goods = ['bash', 'tru'] as const; type test_0_actual = SantasList<typeof bads, typeof goods>; // ^? type test_0_expected = ['tommy', 'trash', 'bash', 'tru']; type test_0 = Expect<Equal<test_0_actual, test_0_expected>>; ``` ## 思路 可以發現必須要讓 `SantasList` 接受外部傳入的型別,所以必須先用泛型別(Generic),動態地傳入外部型別,而且酷的是,在 JavaScript 中使用 ...(spread operator) 合併兩個陣列 `const a = [...arrA, ...arrB]`,在 TypeScript 中定義型別的時候也可以使用。 ```typescript= type SantasList<ListOne, ListTwo> = [...ListOne, ...ListTwo]; ``` 但是當然會出現問題,因為 TypeScript 並不知道傳入的 `<ListOne, ListTwo>` 是否為陣列,所以會出現 `A rest element type must be an array type.` 的錯誤,所以現在必須要讓 TypeScript 知道傳入的是陣列: ```typescript= type SantasList<ListOne extends unknown[], ListTwo extends unknown[]> = [...ListOne, ...ListTwo] ``` 解決了傳入是否為陣列的問題後,出現另一個問題了 `Type 'readonly ["tommy", "trash"]' does not satisfy the constraint 'unknown[]'. The type 'readonly ["tommy", "trash"]' is 'readonly' and cannot be assigned to the mutable type 'unknown[]'.` 發現了另一個小小的東西 `as const`。 ### `as const` 以 JavaScript 中,當我們定義一個不可變的常數時,就會使用 `const` 關鍵字。 在 TypeScript 中這個就有 87% 像,當我們使用 `as const`,我們就會建立一個不可變的物件: ```typescript= const listWithAsConst = ['Joe', 'John', 'Peter'] as const listWithAsConst.push('Jessi') // 因為使用 as const,所以 listWithAsConst 不可以被更改 // Property 'push' does not exist on type 'readonly ["Joe", "John", "Peter"]' ``` [範例](https://www.typescriptlang.org/play?#code/MYewdgzgLgBANgS2gdQVAFiArlAghAYXGhgF4YBtAcgCkQBTKgGhlpHTGdYAV6p6ATlQC6AKEQo0mHPiKQoAOgAOWCOgAUtehAgIqASlGjQ8+EiioMs4rHLU6jFmw5cqvfkOEwAhhBgnocXNLdGt5ZVUNLR09fSA) 這個時候只要額外告知 TypeScript 接受的 Generic 是 `readonly` 就行了: ```typescript= type SantasList<ListOne extends readonly unknown[], ListTwo extends readonly unknown[]> = [...ListOne, ...ListTwo] ``` 或者也可以更語意化地使用 `ReadOnlyArray<T>` 處理: ```typescript= type SantasList<ListOne extends ReadonlyArray<unknown>, ListTwo extends ReadonlyArray<unknown>> = [...ListOne, ...ListTwo] ``` ## 參考資料 1. [What does the "as const" mean in TypeScript and what is its use case?](https://stackoverflow.com/questions/66993264/what-does-the-as-const-mean-in-typescript-and-what-is-its-use-case)