---
# System prepended metadata

title: '[TypeScript] Advent Of TypeScript 05'
tags: [Aot2023, TypeScript]

---

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