概要
JavaScriptで書かれたコードをTypeScriptに移行したので、そのときに書き換えた部分をメモします。
変わったこと
setupの書き方
JavaScript
ファイルを新規作成するたびにこれを書くのが大変でした。エディタが自動で書いてくれることもありますが、どちらにせよインデントが増えるので面倒です。
<script>
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
setup() {
// 処理
},
});
</script>
TypeScript
書き方が非常にシンプルになりました。スッキリしてますね。
<script setup lang="ts">
// 処理
</script>
propsの書き方
見やすくはあるのですが、一つのプロパティに4・5行使うのは少し鬱陶しいですね。
JavaScript
<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より少し面倒かもしれません。
<script setup lang="ts">
// 初期値を設定しない場合
const props = defineProps<{
message: string;
count?: number;
names?: string[];
}>();
</script>
<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
を省略して次のような書き方で大丈夫です。
<script setup lang="ts">
defineProps<{
message: string;
count?: number;
names?: string[];
}>();
</script>
変数・関数の扱い
JavaScript
毎回return
に値を書いていくのが面倒ですね。
<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
などで型指定できるのも良いですね。
<script setup lang="ts">
const message = ref<string>('');
function changeMessage(newMessage: string) {
message.value = newMessage;
}
</script>
emitの扱い
JavaScript
setup()
の引数にemit
が入るのが少し気持ち悪いですね。
子コンポーネント
<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>
親コンポーネント
<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
を独立して宣言できるようになりました。
子コンポーネント
<script setup lang="ts">
const emits = defineEmits<{
(e: 'showMessage', message: string): void;
}>();
function showMessage() {
emits('showMessage', 'HelloWorld');
}
</script>
<template>
<button @click="showMessage">
ボタン
</button>
</template>
親コンポーネント
<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
<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側が面倒ですね。型指定の弊害として受け入れるしかないのですが…。
<script setup lang="ts">
// 省略
function updateValue(event: Event): void {
if (event.target instanceof HTMLInputElement) {
emits('update:modelValue', event.target.value);
}
}
</script>
終わりに
結論としては、一部面倒になったところもありますが全体としてはTypeScriptの方がスッキリ書け、型も安全になりました。他にもあったら追記していきます。