# [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)