You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue + TypeScript:如何以类型安全的方式访问组件属性

Vue3 + TypeScript:父组件访问子组件暴露属性的类型问题解决

问题原因

你遇到的TS错误是因为Vue默认的组件实例类型不包含通过context.expose或defineExpose暴露的属性,TypeScript无法自动推断这些额外属性,所以需要手动指定类型。

解决方案1:使用defineExpose(Vue3.2+ 推荐)

defineExpose是Vue3.2引入的语法糖,相比context.expose能更好地被TypeScript识别,无需额外类型声明。

子组件修改:

<script lang="ts">
import { defineComponent, defineExpose } from 'vue';

export default defineComponent({
  name: 'child',
  setup() {
    const myprop = 1;
    // 用defineExpose暴露属性,TypeScript会自动识别
    defineExpose({ myprop });
    return { myprop };
  }
})
</script>

父组件(Options API)修改:

<template>
  <child ref="child" />
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import Child from './child.vue';

// 获取子组件的实例类型
type ChildInstance = InstanceType<typeof Child>;

export default defineComponent({
  name: 'parent',
  mounted() {
    // 类型断言为子组件实例类型
    const child = this.$refs.child as ChildInstance;
    console.log(child.myprop); // 无TS错误
  }
})
</script>

父组件(Composition API)版本:

如果父组件用Composition API,写法更直观:

<template>
  <child ref="child" />
</template>

<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue';
import Child from './child.vue';

type ChildInstance = InstanceType<typeof Child>;

export default defineComponent({
  name: 'parent',
  setup() {
    // 直接给ref指定子组件实例类型
    const child = ref<ChildInstance | null>(null);

    onMounted(() => {
      if (child.value) {
        console.log(child.value.myprop);
      }
    });

    return { child };
  }
})
</script>

解决方案2:兼容context.expose的手动类型声明

如果你坚持使用context.expose,需要手动定义暴露的属性接口,并合并到子组件实例类型中。

子组件修改:

<script lang="ts">
import { defineComponent } from 'vue';

// 定义暴露的属性接口并导出
export interface ChildExposed {
  myprop: number;
}

export default defineComponent({
  name: 'child',
  setup(props, context) {
    const myprop = 1;
    context.expose({ myprop });
    return { myprop };
  }
})
</script>

父组件修改:

<template>
  <child ref="child" />
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import Child, { ChildExposed } from './child.vue';

// 合并子组件默认实例类型和暴露的属性接口
type ChildInstance = InstanceType<typeof Child> & ChildExposed;

export default defineComponent({
  name: 'parent',
  mounted() {
    const child = this.$refs.child as ChildInstance;
    console.log(child.myprop); // 无TS错误
  }
})
</script>

关键说明

  • InstanceType<typeof Child>用于获取子组件的默认实例类型,包含组件的公共属性和方法。
  • 当使用defineExpose时,Vue会自动将暴露的属性合并到组件实例类型中,无需手动声明接口。
  • 类型断言as ChildInstance是告诉TypeScript:this.$refs.child确实是这个类型,包含myprop属性。

内容的提问来源于stack exchange,提问作者Reynicke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 13:04:59