script setup とは、Vue の単一ファイルコンポーネント(.vue ファイル、以下 SFC)で Composition API を短く書くための構文です。 script タグに setup 属性を付けるだけで、トップレベルに書いた変数・関数・import がそのままテンプレートから使えるようになり、props やイベントは defineProps などの「コンパイラマクロ」で宣言します。

この記事では、7つのマクロ(defineProps / defineEmits / defineModel / defineExpose / defineSlots / defineOptions / withDefaults)を「用途・導入バージョン・型の書き方・最小コード」の早見表にまとめました。掲載したコードは Vue 3.5.43 でコンパイルして動かし、出力とエラー文をそのまま載せています。Vue 3.5 の props 分割代入、ジェネリックコンポーネント、v-model の複数指定と修飾子、Options API との対応表まで1ページで確認できます。

script setup マクロの早見表

マクロは import せずにそのまま書けます。コンパイル時に通常のコンポーネント定義へ変換されるため、実行時には関数として残りません。

マクロ 用途 使える版 型の書き方(TypeScript) 最小コード
defineProps 親から受け取る値を宣言 3.2〜 型引数にオブジェクト型を渡す const props = defineProps<{ label: string }>()
withDefaults 型で宣言した props に既定値を付ける 3.2〜 第2引数に既定値のオブジェクト withDefaults(defineProps<Props>(), { title: '無題' })
props 分割代入 props を変数として取り出し、既定値も書く 3.5〜 分割代入の = で既定値 const { count = 0 } = defineProps<{ count?: number }>()
defineEmits 親へ送るイベントを宣言 3.2〜(タプル記法は 3.3〜) イベント名: [引数] の形 const emit = defineEmits<{ change: [value: number] }>()
defineModel v-model 用の双方向の値を宣言 3.4〜 型引数に値の型 const model = defineModel<number>({ default: 0 })
defineExpose 親がテンプレート参照で使える値を公開 3.2〜 渡したオブジェクトから推論 defineExpose({ open, close })
defineSlots スロットとスロット props の型を宣言 3.3〜 型引数にスロット名と関数型 defineSlots<{ default(props: { item: T }): any }>()
defineOptions name や inheritAttrs などを指定 3.3〜 引数はオブジェクト defineOptions({ inheritAttrs: false })
generic 属性 ジェネリックコンポーネント 3.3〜 script タグの属性に書く generic="T extends { id: number }"

3.3〜・3.4〜・3.5〜の表記は、今回公式の API リファレンス(SFC script setup のページ)を開いて確認しました。3.2〜の行は script setup そのものが正式機能になった版で、一般に知られた仕様として記載しています。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Vue script setupの書き方|defineProps等マクロ早見表」

この記事の検証環境

項目 版
vue / @vue/compiler-sfc 3.5.43
@vue/test-utils 2.5.1
jsdom 30.1.1
TypeScript / vue-tsc 5.9.3 / 3.3.12
Node.js 22.22.2

SFC は @vue/compiler-sfc の compileScript でコンパイルし、Node.js 上の jsdom にマウントして動作を確かめました。ブラウザと Vite の開発サーバーでの表示は未実行です。型エラーは vue-tsc --noEmit の出力です。

script setup の基本形をコピペで確認する

まずは props・イベント・v-model を1つずつ持つカウンターです。lang="ts" を付けると型引数で宣言できます。

<!-- Counter.vue -->
<script setup lang="ts">
import { computed } from 'vue'

const props = defineProps<{
  label: string
  step?: number
}>()

const emit = defineEmits<{
  change: [value: number]
}>()

const count = defineModel<number>({ default: 0 })
const doubled = computed(() => count.value * 2)

function add() {
  count.value += props.step ?? 1
  emit('change', count.value)
}
</script>

<template>
  <button @click="add">{{ label }}: {{ count }} (x2 = {{ doubled }})</button>
</template>

親から label="在庫"、:step="3"、v-model に 5 を渡してボタンを1回クリックした結果です。

在庫: 5 (x2 = 10)
change イベント: 5
在庫: 8 (x2 = 16) / 親の値 = 8

change イベントの時点で 5 と表示されているのは、defineModel の値は代入した直後ではなく、親が値を更新して props が流れ直したあとに変わるためです。更新後の値をすぐ使いたい場合は、const next = count.value + step のように自分で計算した値を代入と emit の両方に使うと意図どおりになります。

script setup で押さえる4つのルール

ルール 内容
トップレベルがそのまま公開される 変数・関数・import したコンポーネントは、return なしでテンプレートから使える
マクロは import 不要 defineProps などはコンパイラが処理する。ref や computed は通常どおり import する
インスタンスごとに実行される script setup の中身はコンポーネントが作られるたびに実行される。1回だけ実行したい処理は通常の script ブロックに分ける
外には何も公開されない 親がテンプレート参照で触れるのは defineExpose に渡したものだけ

Options API と script setup の対応表

Options API で書かれたコンポーネントを読み替えるときの対応です。

Options API script setup での書き方
props: { ... } defineProps()
emits: [ ... ] defineEmits()
data() ref() / reactive()
computed: { ... } computed()
methods: { ... } ふつうの関数宣言
watch: { ... } watch() / watchEffect()
mounted() などのフック onMounted() などを import して呼ぶ
components: { ... } import するだけ(登録の記述は不要)
name / inheritAttrs defineOptions({ ... })
expose: [ ... ] defineExpose({ ... })
this.$emit('x') emit('x')(defineEmits の戻り値)
this.$refs.x useTemplateRef('x')(3.5〜)または同名の ref(null)
this.$attrs / this.$slots useAttrs() / useSlots()
model + update:modelValue の手書き defineModel()

script setup には this がありません。そのぶん、値の出どころが import と変数宣言だけで追えるようになります。

defineProps:props を宣言する3つの書き方

書き方 コード 向いている場面
型で宣言(型ベース) defineProps<{ label: string; step?: number }>() TypeScript を使う場合の基本
実行時オブジェクトで宣言 defineProps({ label: { type: String, required: true } }) JavaScript の場合、validator を使う場合
配列で宣言 defineProps(['label', 'step']) 試作など、型を付けない場合

型ベースで書いても、コンパイラが実行時の props 定義を生成します。そのため、必須の props を渡さなかったり型が合わなかったりすると、開発時は次の警告が出ます(label を渡さず、step に文字列 "3" を渡した実行結果)。

[Vue warn]: Missing required prop: "label" 
  at <Counter step="3" ref="VTU_COMPONENT" > 
  at <VTUROOT>
[Vue warn]: Invalid prop: type check failed for prop "step". Expected Number with value 3, got String with value "3". 
  at <Counter step="3" ref="VTU_COMPONENT" > 
  at <VTUROOT>

型引数と実行時宣言を併用するとコンパイルエラーになる

型引数とオブジェクトの両方を渡すと、コンパイルの段階で止まります。

<script setup lang="ts">
const props = defineProps<{ label: string }>({
  label: { type: String, required: true },
})
</script>
[@vue/compiler-sfc] defineProps() cannot accept both type and non-type arguments at the same time. Use one or the other.

ErrBoth.vue
1  |  <script setup lang="ts">
2  |  const props = defineProps<{ label: string }>({
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3  |    label: { type: String, required: true },
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4  |  })
   |  ^^

defineEmits でも同じです。

[@vue/compiler-sfc] defineEmits() cannot accept both type and non-type arguments at the same time. Use one or the other.

直し方は「どちらか一方に寄せる」です。TypeScript なら型引数だけにして、既定値は次の節の方法で付けます。また、defineProps を1つのコンポーネントで2回呼ぶと duplicate defineProps() call というエラーになるので、props は1つの型にまとめます。

既定値の付け方:withDefaults と props 分割代入(3.5)

型ベースの宣言には default を書く場所がないため、既定値は別の方法で指定します。

withDefaults(3.4 以前からある書き方)

<!-- WithDefaults.vue -->
<script setup lang="ts">
interface Props {
  title?: string
  tags?: string[]
}
const props = withDefaults(defineProps<Props>(), {
  title: '無題',
  tags: () => ['未分類'],
})
</script>

<template>
  <p>{{ props.title }} / {{ props.tags.join(',') }}</p>
</template>

props なしでマウントした場合と、両方渡した場合の結果です。

無題 / 未分類
議事録 / 会議

配列やオブジェクトの既定値は、インスタンス間で同じ参照を共有しないよう関数で返します。

props 分割代入と既定値(Vue 3.5〜)

Vue 3.5 からは、defineProps の戻り値を分割代入した変数がリアクティブなまま使えます。既定値は JavaScript の分割代入の構文で書けます。

<!-- Destructure.vue -->
<script setup lang="ts">
import { watch, watchEffect } from 'vue'

const { count = 0, label = '件数' } = defineProps<{
  count?: number
  label?: string
}>()

watchEffect(() => console.log(`[watchEffect] ${label} = ${count}`))
watch(() => count, (v, old) => console.log(`[watch getter] ${old} -> ${v}`))
</script>

<template>
  <p>{{ label }}: {{ count }}</p>
</template>

props なしでマウントし、count を 3 に、続けて label を「在庫数」に変えたときの出力です。

[watchEffect] 件数 = 0
件数: 0
[watchEffect] 件数 = 3
[watch getter] 0 -> 3
件数: 3
[watchEffect] 在庫数 = 3
在庫数: 3

変数なのに追従できるのは、コンパイラが count を __props.count に書き換えているからです。コンパイル後のコードを見ると確認できます。

watchEffect(() => console.log(`[watchEffect] ${__props.label} = ${__props.count}`));
watch(() => __props.count, (v, old) => console.log(`[watch getter] ${old} -> ${v}`));

分割代入した変数を watch にそのまま渡すとエラーになる

書き換えの結果、watch(count, ...) は「数値そのもの」を渡すことになるため、コンパイラが先に知らせてくれます。

[@vue/compiler-sfc] "count" is a destructured prop and should not be passed directly to watch(). Pass a getter () => count instead.

ErrWatch.vue
2  |  import { watch } from 'vue'
3  |  const { count = 0 } = defineProps<{ count?: number }>()
4  |  watch(count, (v) => console.log(v))
   |        ^^^^^

直し方は watch(() => count, ...) とゲッター関数で包むことです。自作のコンポーザブルに渡すときも同じで、useSomething(() => count) の形にします。

分割代入した props へ代入しようとした場合も、コンパイル時に止まります。

[@vue/compiler-sfc] Cannot assign to destructured props as they are readonly.

ErrAssign.vue
2  |  const { count = 0 } = defineProps<{ count?: number }>()
3  |  function reset() {
4  |    count = 0
   |    ^^^^^

値を変えたいときは、親へイベントを送るか、次に紹介する defineModel を使います。

なお、分割代入と withDefaults を同時に書くと、次の警告が出て分割代入のリアクティブな扱いが無効になります。どちらか一方を選びます。

[@vue/compiler-sfc] withDefaults() is unnecessary when using destructure with defineProps().
Reactive destructure will be disabled when using withDefaults().
Prefer using destructure default values, e.g. const { foo = 1 } = defineProps(...). 

分割代入でリアクティブ性が消える例と直し方

リアクティブなまま使えるのは、defineProps() の戻り値をその場で分割代入した場合だけです。いったん props に受けてから分割代入すると、ふつうの JavaScript の分割代入になり、その時点の値のコピーになります。

<!-- LostReactivity.vue -->
<script setup lang="ts">
import { computed, toRefs } from 'vue'

const props = defineProps<{ count: number }>()

const { count } = props                    // (A) ふつうの分割代入:その時点の値のコピー
const doubledA = computed(() => count * 2)

const { count: countRef } = toRefs(props)  // (B) toRefs:ref として取り出す
const doubledB = computed(() => countRef.value * 2)

const doubledC = computed(() => props.count * 2) // (C) props.count を直接読む
</script>

<template>
  <p>A={{ doubledA }} B={{ doubledB }} C={{ doubledC }}</p>
</template>

count を 1 でマウントし、5 に変えたときの結果です。

count=1: A=2 B=2 C=2
count=5: A=2 B=10 C=10

A だけが 2 のまま変わりません。書き方ごとの違いをまとめます。

書き方 props の変更に追従 補足
const { count } = defineProps() する(3.5〜) コンパイラが props.count に書き換える
const props = defineProps() → props.count する どの版でも使える基本形
const { count } = toRefs(props) する count.value で読む
const { count } = props しない その時点の値のコピーになる
const n = props.count(トップレベル) しない 初期値として使いたいときだけ

defineEmits:イベントを型つきで宣言する

// 3.3〜の短い書き方(名前つきタプル)
const emit = defineEmits<{
  change: [value: number]
  remove: []                          // 引数なし
  rename: [id: number, name: string]  // 引数2つ
}>()

// 関数の呼び出しシグネチャで書く形(3.2 から使える)
const emit2 = defineEmits<{
  (e: 'change', value: number): void
}>()

// 実行時宣言(JavaScript でも使える)
const emit3 = defineEmits(['change', 'remove'])

型で宣言しておくと、親が受け取るハンドラの引数の型まで検査されます。型エラーの例は後半の「型エラーを vue-tsc で確認する」に載せました。

defineModel:v-model を1行で受け取る(3.4〜)

defineModel は、props の modelValue とイベント update:modelValue をまとめて宣言し、ref として返します。model.value に代入すると親の値が更新されます。

書き方 親側の指定 意味
defineModel<number>() v-model="n" 既定の v-model
defineModel<number>({ default: 0 }) v-model="n"(省略可) 既定値つき
defineModel<string>('title', { required: true }) v-model:title="t" 名前つき。複数並べられる
const [model, modifiers] = defineModel<string, 'trim'>() v-model.trim="s" 修飾子を受け取る

v-model を複数指定し、修飾子も受け取る

<!-- RangeField.vue -->
<script setup lang="ts">
// v-model:min / v-model:max の2つと、v-model:keyword.trim.upper の修飾子
const min = defineModel<number>('min', { required: true })
const max = defineModel<number>('max', { required: true })

const [keyword, keywordModifiers] = defineModel<string, 'trim' | 'upper'>('keyword', {
  default: '',
  set(value) {
    let v = value
    if (keywordModifiers.trim) v = v.trim()
    if (keywordModifiers.upper) v = v.toUpperCase()
    return v
  },
})
</script>

<template>
  <input class="min" type="number" v-model.number="min" />
  <input class="max" type="number" v-model.number="max" />
  <input class="kw" v-model="keyword" />
</template>
<!-- RangeParent.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import RangeField from './RangeField.vue'

const min = ref(1)
const max = ref(10)
const keyword = ref('')
</script>

<template>
  <RangeField v-model:min="min" v-model:max="max" v-model:keyword.trim.upper="keyword" />
  <p class="out">{{ min }}〜{{ max }} / [{{ keyword }}]</p>
</template>

入力欄に 3、8、前後に空白を付けた「 vue 」を入れる前と後の、親の表示です。

1〜10 / []
3〜8 / [VUE]

upper は Vue に組み込みの修飾子ではなく、この例で独自に決めた名前です。独自の修飾子は defineModel の2つ目の戻り値で有無を調べ、set オプションで値を加工します(読むときに加工する get もあります)。

defineModel に default を付け、親が v-model を指定しなかった場合、子は既定値、親は undefined という食い違いが起きることがあります。親でも同じ初期値を持つか、required: true にしておくと状態がそろいます。

defineExpose・defineSlots・defineOptions を1つの例で確認する

ダイアログのコンポーネントで3つをまとめて使います。

<!-- Dialog.vue -->
<script setup lang="ts">
import { ref } from 'vue'

defineOptions({ name: 'AppDialog', inheritAttrs: false })

defineSlots<{
  default(props: { close: () => void }): any
  footer?(props: { opened: boolean }): any
}>()

const opened = ref(false)
const secret = ref('外からは見えない値')
function open() { opened.value = true }
function close() { opened.value = false }

defineExpose({ open, close, opened })
</script>

<template>
  <section v-if="opened" class="dialog" v-bind="$attrs">
    <slot :close="close" />
    <footer><slot name="footer" :opened="opened">既定のフッター</slot></footer>
  </section>
</template>
<!-- DialogParent.vue -->
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import Dialog from './Dialog.vue'

const dialog = useTemplateRef('dialog')
defineExpose({ dialog })
</script>

<template>
  <button class="opener" @click="dialog?.open()">開く</button>
  <Dialog ref="dialog" data-test="d1">
    <template #default="{ close }">
      <button class="closer" @click="close">閉じる</button>
    </template>
  </Dialog>
</template>

「開く」を押し、公開された内容を調べ、「閉じる」を押したときの実行結果です。

name: AppDialog / inheritAttrs: false
開く前: "<button class=\"opener\">開く</button>\n<!--v-if-->"
開いた後: <section class="dialog" data-test="d1"><button class="closer">閉じる</button> <footer>既定のフッター</footer> </section>
公開されたキー: [ 'open', 'close', 'opened' ] / secret: undefined / opened: true
閉じた後 section: false
マクロ この例での役割 結果から読み取れること
defineExpose open / close / opened を親に公開 公開していない secret は undefined。公開した ref は自動で中身が取り出される(opened: true)
defineSlots スロット props の型を宣言 親の #default="{ close }" に型が付く。実行時の動作は変えない(型のための宣言)
defineOptions name と inheritAttrs を指定 inheritAttrs: false にして v-bind="$attrs" で渡したので、data-test が section に付いた

defineOptions には props・emits・expose・slots は書けません。それぞれ専用のマクロで宣言します。

ジェネリックコンポーネント:generic 属性の書き方(3.3〜)

script タグの generic 属性に型引数を書くと、渡された props から型が推論されるコンポーネントを作れます。

<!-- SelectList.vue -->
<script setup lang="ts" generic="T extends { id: number }">
const { items } = defineProps<{ items: T[] }>()
const selected = defineModel<T | null>({ default: null })
const emit = defineEmits<{ pick: [item: T] }>()

function pick(item: T) {
  selected.value = item
  emit('pick', item)
}
</script>

<template>
  <ul>
    <li v-for="item in items" :key="item.id" :class="{ on: selected?.id === item.id }" @click="pick(item)">
      <slot :item="item">{{ item.id }}</slot>
    </li>
  </ul>
</template>

items に [{ id: 1, name: '椅子' }, { id: 2, name: '机' }] を渡し、スロットで item.name を表示して2件目をクリックした結果です。

<ul> <li class="">椅子</li> <li class="on">机</li> </ul>
pick: [[{"id":2,"name":"机"}]] update: [[{"id":2,"name":"机"}]]
書きたいこと generic 属性の値
型引数1つ generic="T"
制約つき generic="T extends { id: number }"
複数 generic="T extends string, U extends Item"

generic は lang="ts" と組み合わせて使います。props・emit・v-model・スロットのすべてで同じ T が共有されるので、親側では pick イベントの引数やスロットの item に、渡した配列の要素の型がそのまま付きます。

型エラーを vue-tsc で確認する

テンプレートの型検査は vue-tsc で行います。次の親コンポーネントには、わざと合わない指定を4つ入れてあります。

<!-- TypeErr.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import Counter from './Counter.vue'
import SelectList from './SelectList.vue'

const n = ref(0)
const names = ['椅子', '机']
function onChange(value: string) {}
</script>

<template>
  <Counter v-model="n" />
  <Counter label="在庫" :step="'3'" v-model="n" />
  <Counter label="在庫" v-model="n" @change="onChange" />
  <SelectList :items="names" />
</template>
npx vue-tsc --noEmit -p tsconfig.json
TypeErr.vue(12,4): error TS2345: Argument of type '{ modelValue: number; }' is not assignable to parameter of type '{ readonly label: string; readonly step?: number | undefined; readonly modelValue?: number | undefined; readonly onChange?: ((value: number) => any) | undefined; readonly "onUpdate:modelValue"?: ((value: number) => any) | undefined; } & VNodeProps & AllowedComponentProps & ComponentCustomProps & Record<...>'.
  Property 'label' is missing in type '{ modelValue: number; }' but required in type '{ readonly label: string; readonly step?: number | undefined; readonly modelValue?: number | undefined; readonly onChange?: ((value: number) => any) | undefined; readonly "onUpdate:modelValue"?: ((value: number) => any) | undefined; }'.
TypeErr.vue(13,24): error TS2322: Type 'string' is not assignable to type 'number'.
TypeErr.vue(14,36): error TS2322: Type '(value: string) => void' is not assignable to type '(value: number) => any'.
  Types of parameters 'value' and 'value' are incompatible.
    Type 'number' is not assignable to type 'string'.
TypeErr.vue(15,16): error TS2322: Type 'string[]' is not assignable to type '{ id: number; }[]'.
  Type 'string' is not assignable to type '{ id: number; }'.
行 原因 直し方
12 必須の label を渡していない label を渡す、または型を label?: string にする
13 step に文字列を渡した :step="3" と数値で渡す
14 change のハンドラの引数が string defineEmits の宣言に合わせて number にする
15 generic の制約 { id: number } に合わない配列 id を持つオブジェクトの配列を渡す

1行目のエラー文から、defineModel と defineEmits が props 側に modelValue・onUpdate:modelValue・onChange として現れていることも読み取れます。マクロが何を生成しているかを知る手がかりになります。

エラー文から直し方を引く逆引き表

この記事で再現したメッセージの一覧です。

メッセージ(抜粋) 出る場面 直し方
defineProps() cannot accept both type and non-type arguments at the same time 型引数と実行時宣言を併用 どちらか一方にする
defineEmits() cannot accept both type and non-type arguments at the same time 同上(emits) どちらか一方にする
duplicate defineProps() call defineProps を2回呼んだ 1つの型にまとめる
"count" is a destructured prop and should not be passed directly to watch() 分割代入した props を watch に直接渡した () => count で渡す
Cannot assign to destructured props as they are readonly. 分割代入した props に代入した emit か defineModel で親に更新してもらう
withDefaults() is unnecessary when using destructure with defineProps() 分割代入と withDefaults の併用 分割代入の既定値に寄せる
Missing required prop: "label" 必須 props を渡していない(実行時) 親で渡す、または任意にして既定値を付ける
Invalid prop: type check failed for prop "step" 型の違う値を渡した(実行時) :step="3" のように : を付けて数値で渡す

よくある質問

Q. script setup と通常の script は同じファイルに書けますか? A. 書けます。通常の script ブロックはモジュールの読み込み時に1回だけ実行されるので、名前つき export や、1回だけ行いたい初期化を置く場所として使えます。2つのブロックの lang はそろえます。name や inheritAttrs を指定したいだけなら、defineOptions で script setup の中に書けます。

Q. props の既定値は withDefaults と分割代入のどちらで書けばよいですか? A. Vue 3.5 以上なら分割代入の既定値が短く書けます。3.4 以前にも対応させるコードや、props.xxx の形で統一したいコードでは withDefaults が合います。両方を同時に書くと警告が出るので、コンポーネントごとにどちらかへ寄せます。

Q. defineModel と、defineProps+defineEmits の組み合わせはどう使い分けますか? A. 「親の値を子から書き換える」用途は defineModel が向いています。modelValue と update:modelValue の宣言が1行にまとまります。子からは通知だけを送り、値をどうするかは親に任せたい場合は、defineProps と defineEmits の組み合わせがわかりやすくなります。

Q. defineProps の中でローカル変数を参照できますか? A. マクロの引数は setup の外へ移されてコンパイルされるため、setup 内で宣言した変数に依存する書き方はコンパイルエラーの対象になります(公式の API リファレンスに記載。import した値は参照できます)。今回の確認では、const fallback = 10 のようなリテラルの定数はエラーにならずコンパイルできました。既定値に使う値は、import するかリテラルで書くと確実です。

まとめ

  • script setup は、トップレベルの変数・関数・import がそのままテンプレートで使える構文。props やイベントは import 不要のマクロで宣言する
  • props は defineProps の型引数で宣言。型引数と実行時宣言の併用はコンパイルエラーになるので、どちらか一方にする
  • 既定値は、Vue 3.5 以上なら分割代入(const { count = 0 } = defineProps())、それ以前は withDefaults
  • 分割代入した props を watch やコンポーザブルに渡すときは () => count。const { count } = props はその時点のコピーになり追従しない
  • v-model は defineModel。名前を付ければ複数並べられ、修飾子は2つ目の戻り値と set で扱う
  • 親に公開するのは defineExpose に渡したものだけ。スロットの型は defineSlots、name と inheritAttrs は defineOptions
  • generic 属性で、props・emit・スロットに同じ型引数を通せる。型の検査は vue-tsc --noEmit で行う

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Vue script setupの書き方|defineProps等マクロ早見表」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?