LoginSignup
4
1

More than 1 year has passed since last update.

Vue3でコンポーネントをexportしたらTypeScriptでエラーが発生する

Last updated at Posted at 2022-11-22

はじめに

Vue3を手が空いているときに書くようにして学習を最近しているのですが、Vue3に変わってComposition APIというものが増えていました

そこで今回は詰まった箇所があるので共有します。
なんとなくで書きながら学ぼうとするとふとしたところで結構時間を取られてしまいます。またTypeScript関係のエラーだったのでエラー文からは想像がつきませんでした、、

問題

以下の画面を作成しています

image.png

ここでこの画面のレイアウトはコンポーネントとしており、App.vueでコンポーネントをインポートして表示しようとしています

Login.vue
<script setup lang="ts">
import { defineComponent, ref } from "vue";

export default defineComponent({
  name: "Login",
  setup() {
    const name = ref("");
    const roomNumber = ref();

    const changeName = (e: Event) => {
      if (e.target instanceof HTMLInputElement) {
        console.log(e.target.value);
        name.value = e.target.value;
      }
    };

    const changeRoomNumber = (e: Event) => {
      if (e.target instanceof HTMLInputElement) {
        console.log(e.target.value);
        roomNumber.value = e.target.value;
      }
    };
    return {
      name,
      roomNumber,
      changeName,
      changeRoomNumber,
    };
  },
});
</script>

<template>
  <div>
    <div class="container">
      <h1>チャットに参加する</h1>
    </div>
    <v-row class="container">
      <v-col cols="12">
        <v-form ref="form" lazy-validation>
          <v-text-field
            v-model="name"
            :value="name"
            v-on:input="changeName"
            label="お名前"
            required
            :rules="[(v) => !!v || 'お名前を入力してください']"
          />
        </v-form>
      </v-col>
    </v-row>
    <v-row class="container">
      <v-col cols="12">
        <v-form ref="form" lazy-validation>
          <v-text-field
            v-model="roomNumber"
            :value="roomNumber"
            v-on:input="changeRoomNumber"
            label="ルーム番号"
            required
            :rules="[
              (v) => !!v || 'ルーム番号を入力してください',
              (v) =>
                /^\d{1}$|^\d{2}$/.test(v) ||
                'ルーム番号は2桁以内の数字を入力してください',
            ]"
          />
        </v-form>
      </v-col>
    </v-row>
    <v-row class="container">
      <v-col cols="12">
        <v-btn color="info" block>ルームに参加</v-btn>
      </v-col>
    </v-row>
  </div>
</template>

<style>
.container {
  display: flex;
  justify-content: center;
}
</style>

このようにコンポーネントを作成したのですが、なぜかVSCode上でexportの部分にエラーが表示されます

image.png

エラー内容は以下になります (わけがわからない)

class __VLS_setup.default
enum __VLS_setup.default
module __VLS_setup.default
(enum member) __VLS_setup.default
(enum member) __VLS_setup.default: DefineComponent<{}, {
    name: Ref<string>;
    roomNumber: Ref<any>;
    changeName: (e: Event) => void;
    changeRoomNumber: (e: Event) => void;
}, {}, {}, {}, ComponentOptionsMixin, ... 5 more ..., {}>
既定のエクスポートは、ファイルまたはモジュールの宣言のトップレベルにある必要があります。ts(1258)

ネットを調べたのですが、まったくそれらしい解決策が見つけられませんでした

解決方法

問題はscriptタグに書かれているsetupというメソッドでした

このsetupを使うことでexport default defineComponetの代わりを務めているようなのでsetupを消すことでエラーが消えました

しかし、setupという便利なシンタックスシュガーがあるのでもっとシンプルに以下のように書くことにしました

Login.tsx
<script setup lang="ts">
import { defineComponent, ref } from "vue";

const name = ref("");
const roomNumber = ref();

const changeName = (e: Event) => {
  if (e.target instanceof HTMLInputElement) {
    console.log(e.target.value);
    name.value = e.target.value;
  }
};

const changeRoomNumber = (e: Event) => {
  if (e.target instanceof HTMLInputElement) {
    console.log(e.target.value);
    roomNumber.value = e.target.value;
  }
};
</script>

<template>
  <div>
    <div class="container">
      <h1>チャットに参加する</h1>
    </div>
    <v-row class="container">
      <v-col cols="12">
        <v-form ref="form" lazy-validation>
          <v-text-field
            v-model="name"
            :value="name"
            v-on:input="changeName"
            label="お名前"
            required
            :rules="[(v) => !!v || 'お名前を入力してください']"
          />
        </v-form>
      </v-col>
    </v-row>
    <v-row class="container">
      <v-col cols="12">
        <v-form ref="form" lazy-validation>
          <v-text-field
            v-model="roomNumber"
            :value="roomNumber"
            v-on:input="changeRoomNumber"
            label="ルーム番号"
            required
            :rules="[
              (v) => !!v || 'ルーム番号を入力してください',
              (v) =>
                /^\d{1}$|^\d{2}$/.test(v) ||
                'ルーム番号は2桁以内の数字を入力してください',
            ]"
          />
        </v-form>
      </v-col>
    </v-row>
    <v-row class="container">
      <v-col cols="12">
        <v-btn color="info" block>ルームに参加</v-btn>
      </v-col>
    </v-row>
  </div>
</template>

<style>
.container {
  display: flex;
  justify-content: center;
}
</style>
App.vue
<script setup lang="ts">
import Login from "./components/Login.vue";
</script>

<template>
  <div className="App">
    <Login />
  </div>
</template>

<style>
.App {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

returnで返す必要もないので大助かりです。これならVue3でも楽でいいなと思いました

おわりに

今回はVue3を書いたときにはまったことについてまとめました
他のJavaScriptフレームワーク経験者がなんとなくでVue3を書くと案外はまってしまう落とし穴なのかなと思いました

参考

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1