Subscribe on changes!

type auto resolve when use defineExpose in typescript

avatar
Sep 11th 2022

What problem does this feature solve?

it seems that we must create type for a componet when use defineExpose in typescript , and we can get type hint.

// src/types/index.ts
export type CompInst = {
  getString: () => string;
};
// src/Comp.vue
<script setup lang="ts">
import { CompInst } from "./types";

defineExpose<CompInst>({
  getString() {
    return "hello";
  },
});
</script>

<template>
  <div>comp1</div>
</template>
// src/App.vue
<script setup lang="ts">
import Comp from "./Comp.vue";
import { CompInst } from "./types";

const compRef = ref<CompInst | null>(null);

// type hint !
compRef.value?.getString();
</script>

<template>
  <Comp ref="compRef"></Comp>
</template>

maybe can we resolve type of expose by component directly?

What does the proposed API look like?

// src/App.vue
<script setup lang="ts">
// a inner tool can auto resolve expose type from type of component.
import { resolveExpose } from "vue"
import Comp from "./Comp.vue";


const compRef = ref<resolveExpose<typeof Comp> | null>(null);

// type hint !
compRef.value?.getString();
</script>

<template>
  <Comp ref="compRef"></Comp>
</template>
avatar
Sep 11th 2022

maybe we can use InstanceType<typeof Comp> to get instance type, but it expose many properties that we don't need.

image

avatar
Oct 14th 2022

You could use something like:

export type Constructor<Signature> = abstract new (...args: any) => Signature

// Remove default vue properties from the component ref instance
export type ComponentRef<Component extends Constructor<unknown>> = {
  [
    Key in keyof InstanceType<Component> as
      // Remove vue builtins
      Key extends `$${string}`
        ? never
        // Remove custom directives
        : Key extends `v${Capitalize<string>}`
          ? never
          : Key
  ]: InstanceType<Component>[Key]
}

// usage

const compRef = ref<ComponentRef<typeof Comp> | null>(null);

That should leave you with much less noise by removing all of the vue related properties.

Be wary though, that it will still show all top-level properties, and non-exposed ones will not be available at runtime.