6歳娘「パパ、any型よりunknown型がいいんじゃない？」

# リモートワーク中ワイ

ワイ「あー、いそがし、いそがし・・・と」
ワイ「よし、Slackでこう呟いておけば、仕事してる感が出るやろ」

娘「ねぇ、パパ」
娘「質問していい？」

ワイ「ええで、娘ちゃん」

娘「今、とある会社さんの**コーポレートサイト**を作ってるの」

ワイ「おお、そうなんか」
ワイ「娘ちゃんも、もう小学1年生やもんな」
ワイ「そんな事もできるようになったんやな」

娘「うん」
娘「それで、**TypeScript**について分からないことがあるの」

ワイ「なんや？パパが教えてあげるで」

娘「ありがとう、パパ！」

# 何について困っているのか
娘「実は、クライアントさんから」
娘「こんな要望が来ているの」

> クライアント「以下のような**関数**を作ってほしいです」
>　
> - **引数として、どんな型の値でも受け取れる**
> - 引数がもし配列だったら`pop()`メソッドで末尾の要素を取り出し、戻り値として返す
> - 引数が配列でなかったら、`undefined`を返す

ワイ「ふーん」
ワイ「・・・何のために？」
ワイ「一体どんな会社さんなん？」

娘「**配列だったらポップしてちょうだい株式会社**さんっていうんだけど」

ワイ「**配列だったらポップしてちょうだい株式会社**さん！？」
ワイ「まるで、**この記事のために考えられたかのような**会社名やな」

娘「とにかく、**どんな型の値でも受け取れる**」
娘「そんな関数を作りたいの」

ワイ「なるほど、パパに任せてや！」

# あの型を使ってしまえ

ワイ「じゃあ、まず関数の名前を考えるで」
ワイ「**配列かもしれない**値から、末尾の要素を`pop()`するから」
ワイ「関数名は`popFromMaybeArray`や！」

```diff_typescript
    const popFromMaybeArray = () => {
      /* ここに処理を書く */
    }
```

ワイ「↑こうやな」
ワイ「ほんで、引数としては**どんな型でも受け取りたい**わけやな」
ワイ「そして、返り値の型も不明やから・・・」

```diff_typescript
    const popFromMaybeArray = (maybeArray: any): any => {
      /* ここに処理を書く */
    }
```

ワイ「↑こうや！」
ワイ「`any`型を使ってやるわけや！」
ワイ「これで完璧や！」

娘「パパ、ありがとう！」
娘「ワーイ！」

ワイ「ワーイ！」

# ミスに気づけなさ過ぎて、つらい

娘「パパ、これじゃあやりづらいよ」

ワイ「そうなん・・・？」

娘「だって・・・」

```diff_typescript
    const popFromMaybeArray = (maybeArray: any): any => {
      maybeArray.poppu() // コンパイルエラーなし
      maybeArray.hoge() // コンパイルエラーなし
    }
```

娘「↑ほら」
娘「`any`型だと、どんなに**メソッド名を間違えたりしても**」
娘「コンパイルエラーが出ないから」
娘「ミスに気づけないよ・・・」
娘「せっかくTypeScriptを使っているのに・・・」

ワイ「ほんまやな・・・」

娘「これじゃ、絶対に**実行時エラー**が出ちゃうよ」
娘「型安全性が皆無だよ」

ワイ「Oh・・・」
ワイ「ほな、どうしよう・・・」

娘「あっ」
娘「パパ、もしかして」
娘「`unknown`型を使えばいいんじゃない？」

ワイ「なんやて？<code><ruby>unko<rt>ウンコ</rt></ruby></code>...？」

娘「**<code><ruby>unknown<rt>アンノウン</rt></ruby></code>型**よ」

ワイ「ああ、そっちか」

# `unknown`型を使ってみる

娘「えっと、`any`型だったところを」
娘「`unknown`型にするから・・・」

```diff_typescript
    const popFromMaybeArray = (maybeArray: unknown): unknown => {
      /* 省略 */
    }
```

娘「↑こうだね！」
娘「ほら、コンパイルエラーが表示されたよ！」

![スクリーンショット 2022-05-21 10.29.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/677b7b08-25a3-1004-cd63-03f58fbd4499.png)


ワイ「へー」
ワイ「`unknown`型は、何でも受け取れるけど」
ワイ「`any`みたいに何でも許してしまう訳ではなくて」
ワイ「ちゃんとコンパイルエラーを出してくれるんやな」
ワイ「`any`の**型安全版**って感じ？」

娘「そうだね」

ワイ「なるほどな」
ワイ「`unknown`、つまり**不明**な値やから」
ワイ「`poppu()`メソッドや`hoge()`メソッドを持ってるかは分からへんから」
ワイ「実行できません、ってことをエラーで教えてくれてる感じやな？」
ワイ「ほな、どうすればええんやろ？」

娘「えっとね」
娘「引数が配列じゃなかった場合には先に進めないように、**型ガード**してやればいいんだよ」

ワイ「と言いますと・・・？」

娘「見ててね」

```diff_typescript
    const popFromMaybeArray = (maybeArray: unknown): unknown => {
+     // 引数が配列じゃない場合には、早期return。
+     if (!Array.isArray(maybeArray)) return undefined
      maybeArray.poppu()
      maybeArray.hoge()
    }
```

娘「↑こうだね！」

ワイ「なるほど」
ワイ「配列かどうか、`Array.isArray()`でチェックして」
ワイ「配列じゃない場合には、**早期リターン**してやるんやな」

娘「そうだよ」
娘「こうしてあげると・・・」

![スクリーンショット 2022-05-21 10.42.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/7b2d24b6-f773-ec1a-3a15-16d6669ec6bc.png)

娘「ほら、メソッド名の間違いを指摘してくれたよ」

ワイ「なるほどな」
ワイ「`maybeArray`が**配列であること**が確定したから」

> TSコンパイラ「配列は`poppu`なんて持ってないですよ」

ワイ「って指摘してくれたわけやな」
ワイ「型安全な感じになってきたな」

娘「うん」
娘「あとは、末尾の要素を`pop()`して」
娘「返してあげればいいから・・・」

```diff_typescript
    const popFromMaybeArray = (maybeArray: unknown): unknown => {
      // 引数が配列じゃない場合には、早期return。
      if (!Array.isArray(maybeArray)) return undefined
+     // 末尾の要素を取得。
+     const lastItem: unknown = maybeArray.pop()
+     return lastItem
    }
```

娘「↑こうだね！」

# 動作確認してみる

```diff_typescript
// 配列を渡してみる
const a = popFromMaybeArray([1, 2, 3])
console.log(a) // -> 3

// 文字列を渡してみる
const b = popFromMaybeArray("文字列")
console.log(b) // -> undefined
```

娘「うん」
娘「配列を渡した場合には、末尾の要素が返ってくるし」
娘「そうじゃない場合には、`undefined`が返ってきてる」

ワイ「おお、ほんまや！」
ワイ「これで、**配列だったらポップしてちょうだい株式会社**さんも大喜びやな！」

娘「うん！」
娘「さっそく**配ポップ**さんに連絡してみる！」

ワイ「**配ポップ**さんって呼んでるんや」

# まとめ
- `unknown`型とは
  - どんな型の値でも代入できる
  - でも`any`型と違って**型安全**
  - `unknown`型のままでは何もできない
    - `if`文などで型を絞り込んでやることで色々できる
  - どんな値が来るのか不明な場合に使える

# その日の夜

ワイ「なるほどなぁ」
ワイ「どんな型でも受け取りたい場合は`any`を使うしかないのかと思ってたわ」
ワイ「型安全な`unknown`なんていう型もあったんやなぁ」

娘「そうだね」
娘「ところでパパ、今日お仕事だったんでしょ？」
娘「私と話してばっかりで、殆どお仕事してなかったんじゃない？」
娘「今日、コードは何行書いたの？」

ワイ「実は・・・まだ**0行**や・・・グビッ（ビールを飲む音）」
ワイ「アレや」
ワイ「最近話題の・・・**ノーコード**いうやつやな」

娘「ノーコード・・・聞いたことある！」
娘「パパ、ノーコードで稼いでるんだ！」
娘「すご〜い！」

ワイ「ワーイ！」

よめ太郎「それ給料泥棒やないかい」

**〜おしまい〜**

# 注意
- 引数で受け取った配列に対して`pop()`等の破壊的操作を行うとバグの温床になるので、普通はやめましょう。
- **配ポップ社**さんの案件のときだけにしましょう。

# 新しい記事もよろしくやで
- [WHERE句を忘れただけなのに](https://qiita.com/Yametaro/items/c592460034b0e5bc131a)
- [6歳娘「パパ、条件によって変わる型を作りたいの」](https://qiita.com/Yametaro/items/9b2f0ab2037450004816)

# Zennにも記事を書いてみましたやで
- [独り言形式で綴る「OGP & SSR」](https://zenn.dev/tokumoto/articles/0098b3e850676f)

# noteも書いてますやで

- [ワイ「三角関数って、要らなくね？」](https://note.com/yametaro/n/n4ad2f07cde72)