【TypeScript&Nuxt.js】占いアプリ②カードを引く関数を作る

# 前回はこちら
https://qiita.com/sakuc47/items/60f7a3d3b9500059030e

### 進め方

1.	タロットカードのデータをTypeScriptで配列にする ✅
2.	**その中からランダムに1枚選ぶロジックを書く** 👈今回はこれ
3.	結果を表示する画面を作る（1ページ）
4.	カードごとに画像を表示してみる	
5.	NuxtLinkでページ遷移（トップ→結果ページ）
6.	デザインを整える
7.	応用：今日の運勢APIを取り入れてみる
8.	データの組み合わせで文章を作る

# ステップ2.用意したカードの中からランダムに1枚選ぶロジックを書く
ざっと雛形。
``` ts
<template>
  <div class="p-fortune-contents">
    <h1>タロット占い🔮</h1>
    <button @click="drawCard">カードを引く</button>

    <div class="p-results">
      <h2>今日の運勢</h2>
      <div class="p-results-card">
        <p>カードの番号</p>
        <p>カードの名前</p>
        <p>カードの内容</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
</script>

<style scoped>
</style>
```

「今日の運勢」の下に引いたタロットカードの情報を入れたい。→refを使う！

### ▼refの型付け
TSでrefを使うので、下記の公式ドキュメントの【refの型付け】を参考にする。

https://ja.vuejs.org/guide/typescript/composition-api.html#typing-ref

自分で考えて書いてみたが、GPTに聞いたら修正箇所の指摘が入った。
```ts
// 間違い
const selectedCard: Ref<number | string > = ref(null)

// ↓

// 修正後
const selectedCard: Ref<number | string | null> = ref(null)
```

:::note warn
ref(null) と書いてるのに、型には null が含まれてない
:::

＜考え方＞
- ref(null) は「初期値として null を入れる」という意味

- Ref<number | string> は「中に number か string しか入らない箱」という意味

### ▼ランダムにカードを1枚引く関数 `drawCard()` を作る

このようなボタンを作った。
```vue
    <button @click="drawCard">カードを引く</button>
```

＜やりたいこと＞
- ボタンを押下したら`drawCard`が動く
- `tarotCards`からカードをランダムに一枚引く（`Math.random`を使う）
- 表か裏かをランダムに決める
- 引いたカードのid、名前、内容（表か裏のどちらか）を「今日の運勢」の下に表示させる

`Math.random`を使うんだろうな、ということはわかったけど、実際の書き方が全然思い浮かばなかった。。😢
GPTにレクチャーをお願いした。


①Math.random() は 0 以上 1 未満の「小数」を返してくれる関数

``` js
Math.random() // 0.2857 や 0.9991 や 0.0032 のような数
```

②これを使って**インデックス番号**を作る！
たとえばカードが 22枚あるなら、配列のインデックスは 0 〜 21 。
``` ts
const index = Math.floor(Math.random() * 22)
```

- Math.random() * 22 → 0〜21.999...
- Math.floor(...) → 小数点以下を切り捨てて、0〜21の整数になる！

③ `tarotCards.length` で枚数を自動で取得（22って決め打ちしない）
（今回はタロットだから決められた枚数ではあるけど）

```ts 
const index = Math.floor(Math.random() * tarotCards.length)
const card = tarotCards[index]
```

これらを `drawCard`関数として使うので
```ts
// カードを一枚選ぶ関数 drawCard
function drawCard () {
  const index = Math.floor(Math.random() * tarotCards.length)
  const card = tarotCards[index]
  selectedCard.value = card
}
 ```
ここでTSエラーが出た。

:::note warn
 型 'TarotCard' を型 'string | number | null' に割り当てることはできません。 
:::


これは、宣言している selectedCard の型は
`const selectedCard: Ref<string | number | null> = ref(null)
 ` 
↑こうなっているけど、実際に代入してる card は `TarotCard 型`のオブジェクト
```ts
export const tarotCards: TarotCard[] = [
  {
    id: 0,
    name: '愚者（The Fool）',
    normalMeaning: '自由、冒険、無限の可能性',
    reverseMeaning: '無計画、不安定、軽率',
  },
```

`selectedCard` の宣言を修正する。
```ts
<script setup lang="ts">
import { tarotCards, TarotCard } from '@/data/tarotCards'
import { ref, type Ref } from 'vue' // ref型を使う

// 選ばれたカード の型付け
// const selectedCard: Ref<number | string | null> = ref(null);
const selectedCard: Ref<TarotCard | null> = ref(null)

// カードを一枚選ぶ関数 drawCard
function drawCard() {
  const index = Math.floor(Math.random() * tarotCards.length)
  const card = tarotCards[index]
  selectedCard.value = card
}
</script>
```

そうすると、またTSエラーが出た。。

:::note warn
'TarotCard' は型であり、'verbatimModuleSyntax' が有効であるときは、型のみのインポートを使用してインポートされる必要があります。
:::

調べたら、**TypeScript の「型は型だけとしてインポートすること」** というルールによるもの。

import部分を修正する。

``` import { tarotCards, type TarotCard } from '@/data/tarotCards' ```


次は引いたカードの内容を表示させる！