Composition APIにおいて、JavaScriptからTypeScriptにして変わったこと

## 概要
JavaScriptで書かれたコードをTypeScriptに移行したので、そのときに書き換えた部分をメモします。

## 変わったこと
### setupの書き方
#### JavaScript
ファイルを新規作成するたびにこれを書くのが大変でした。エディタが自動で書いてくれることもありますが、どちらにせよインデントが増えるので面倒です。
```vue
<script>
import { defineComponent } from '@vue/composition-api';

export default defineComponent({
  setup() {
    // 処理
  },
});
</script>
```

#### TypeScript
書き方が非常にシンプルになりました。スッキリしてますね。
```vue
<script setup lang="ts">
// 処理
</script>
```

### propsの書き方
見やすくはあるのですが、一つのプロパティに4・5行使うのは少し鬱陶しいですね。
#### JavaScript
```vue
<script>
import { defineComponent } from '@vue/composition-api';

export default defineComponent({
  props: {
    message: {
      type: String,
      required: true,
      default: 'Hello World',
    },
    count : {
      type: Number,
      required: false,
      default: 1,
    },
    names: {
      type: Array,
      required: false,
    },
  },
  setup() {
    // 処理
  },
});
</script>
```

#### TypeScript
一つのプロパティが1行で済むので助かります。ただ、初期値を設定する場合はJavaScriptより少し面倒かもしれません。

```vue
<script setup lang="ts">
// 初期値を設定しない場合
const props = defineProps<{
  message: string;
  count?: number;
  names?: string[];
}>();
</script>
```
```vue
<script setup lang="ts">
// 初期値を設定する場合
export interface Props {
  message: string;
  count?: number;
  names?: string[];
}
const props = withDefaults(defineProps<Props>(), {
  message: 'Hello World',
  count: 1,
  names: () => [],
});
</script>
```

**[追記]**
ESLintを利用している場合、上のコードだと``'props' is assigned a value but never used``というエラーが出てしまいます。scriptタグ内で``props``を利用せずtemplateタグのみで利用する場合は、``const props``を省略して次のような書き方で大丈夫です。
```vue
<script setup lang="ts">
defineProps<{
  message: string;
  count?: number;
  names?: string[];
}>();
</script>
```



## 変数・関数の扱い
#### JavaScript
毎回``return``に値を書いていくのが面倒ですね。
```vue
<script>
import { defineComponent } from '@vue/composition-api';

export default defineComponent({
  setup() {
    const message = ref('');

    function changeMessage(newMessage) {
      message.value = newMessage;
    }

    return {
      message,
      changeMessage,
    }
  },
});
</script>
```

#### TypeScript
``return``が必要なくなりスッキリしました。また、関数の引数や戻り値、``ref``などで型指定できるのも良いですね。
```vue
<script setup lang="ts">
const message = ref<string>('');
function changeMessage(newMessage: string) {
  message.value = newMessage;
}
</script>
```


## emitの扱い
#### JavaScript
``setup()``の引数に``emit``が入るのが少し気持ち悪いですね。
##### 子コンポーネント
```vue:ChildComponent.vue
<script>
import { defineComponent } from '@vue/composition-api';

export default defineComponent({
  setup(props, { emit }) {
    function showMessage() {
      emit('showMessage', 'HelloWorld');
    }

    return {
      showMessage,
    };
  },
});
</script>

<template>
  <button @click="showMessage">
    ボタン
  </button>
</template>
```

##### 親コンポーネント
```vue:ParentComponent.vue
<script>
import { defineComponent, ref } from '@vue/composition-api';

export default defineComponent({
  setup(props) {
    const message = ref('');
    function showMessage(newMessage) {
      message.value = newMessage;
    }

    return {
      message,
      showMessage,
    };
  },
});
</script>

<template>
  <p>{{ message }}</p>
  <child-component @showMessage="showMessage" />
</template>
```

#### TypeScript
``emits``を独立して宣言できるようになりました。
##### 子コンポーネント
```vue:ChildComponent.vue
<script setup lang="ts">
const emits = defineEmits<{
  (e: 'showMessage', message: string): void;
}>();
function showMessage() {
  emits('showMessage', 'HelloWorld');
}
</script>

<template>
  <button @click="showMessage">
    ボタン
  </button>
</template>
```

##### 親コンポーネント
```vue:ParentComponent.vue
<script setup lang="ts">
const message = ref<string>('');
function showMessage(newMessage: string) {
  message.value = newMessage;
}
</script>

<template>
  <p>{{ message }}</p>
  <child-component @showMessage="showMessage" />
</template>
```

## eventの扱い
#### JavaScript
```vue
<script>
import { defineComponent, ref } from '@vue/composition-api';

export default defineComponent({
    // 省略
    setup(props) {
    function updateValue(event) {
      emits('update:modelValue', event.target.value);
    }
    // 省略
  },
});
</script>
```

#### TypeScript
これに関してはTypeScript側が面倒ですね。型指定の弊害として受け入れるしかないのですが…。
```vue
<script setup lang="ts">
// 省略
function updateValue(event: Event): void {
  if (event.target instanceof HTMLInputElement) {
    emits('update:modelValue', event.target.value);
  }
}
</script>
```

## 終わりに
結論としては、一部面倒になったところもありますが全体としてはTypeScriptの方がスッキリ書け、型も安全になりました。他にもあったら追記していきます。