Home  >  Article  >  Web Front-end  >  How to solve the problem of vue3 getting ref instance combined with ts InstanceType

How to solve the problem of vue3 getting ref instance combined with ts InstanceType

WBOY
WBOYforward
2023-05-20 22:59:321692browse

    vue3 Gets the ref instance and combines it with the InstanceType of ts

    Sometimes we have template references, but when using them, the ts prompt does not work, and there is no prompt for the component to pass The method name exposed by defineExpose, although this is not very influential, it can be solved or solved~

    <!-- MyModal.vue -->
    <script setup lang="ts">
    import { ref } from &#39;vue&#39;
    
    const sayHello = () => (console.log(&#39;我会说hello&#39;))
    
    defineExpose({
      sayHello
    })
    </script>

    Then we use it at the parent level. After entering MyModalRef.value, we will find that there is no sayHello function prompt, so at this time We need to use the InstanceType tool type to get its instance type

    <!-- App.vue -->
    <script setup lang="ts">
    import MyModal from &#39;./MyModal.vue&#39;
    const MyModalRef = ref()
    
    const handleOperation = () => {
      MyModalRef.value.sayHello
    }
    </script>

    How to solve the problem of vue3 getting ref instance combined with ts InstanceType

    Use the InstanceType tool type to get its instance type:

    <!-- MyModal.vue -->
    <script setup lang="ts">
    import { ref } from &#39;vue&#39;
    
    const sayHello = () => (console.log(&#39;我会说hello&#39;))
    
    defineExpose({
      open
    })
    </script>

    Parent use

    <!-- App.vue -->
    <script setup lang="ts">
    import MyModal from &#39;./MyModal.vue&#39;
    
    const MyModalRef = ref<InstanceType<typeof MyModal> | null>(null)
    
    const handleOperation = () => {
      MyModalRef.value?.sayHello()
    }
    </script>

    It seems that there is still no prompt to use InstanceType when prompted, and then input the wrong content and no error is reported before compilation..., but Vue official said this, then just listen to him (in fact, I generally don’t use it, but Also learned)

    @vue official API annotates component template reference types

    How to annotate TS types for vue3 components

    Vue3 and TS are definitely the most popular this year front-end technology. Many companies are using Vue3 TS Vite combination to develop new projects. The following is the rewritten sentence: Share how to use Composition-Api combined with TS types in Vue3 components.

    Annotate the type for props

    Use

    When using

    <script setup lang="ts">
    const props = defineProps({
      foo: { type: String, required: true },
      bar: Number
    })
     
    props.foo // string
    props.bar // number / undefined
    </script>

    This is called a runtime declaration because the parameters passed to defineProps() will be used as runtime props options.

    The second way is to define the type of props through generic parameters, which is more direct:

    <script setup lang="ts">
    const props = defineProps<{
      foo: string
      bar?: number
    }>()
    </script>
     
    /* or
    <sctipt setup lang="ts">
    interface Props {
      foo: string
      bar?: number
    }
    const props = defineProps<Props>()
    </script>
    */

    The compiler will try to deduce the type parameters and generate corresponding runtime options. This approach is called type-based declaration. The disadvantage of this approach is that the ability to define default values ​​for props is lost. Using the withDefaults compiler can solve this problem

    interface Props {
      msg?: string
      labels?: string[]
    }
     
    const props = withDefaults(defineProps<Props>(), {
      msg: &#39;hello&#39;,
      label: () => [&#39;one&#39;, &#39;two&#39;]
    })

    The above code will be compiled into the equivalent default option of runtime props.

    Non

    If

    import { defineComponent } from &#39;vue&#39;
     
    export default defineComponent({
      props: {
        message: String
      },
      setup(props){
        props.message // 类型:string
      }
    })

    Annotate the type for emits

    Use

    In

    <script setup lang="ts">
    // 运行时
    const emit = defineEmits([&#39;change&#39;, &#39;update&#39;])
     
    //基于类型
    const emit = defineEmits<{
      (e: &#39;change&#39;, id: number): void
      (e: &#39;update&#39;, value: string): void
    }>()
    </script>

    We can see that type-based declaration allows us to have more fine-grained control over the type of triggered events.

    Non

    If

    import { defineComponent } from &#39;vue&#39;
     
    export default definComponent({
      emits: [&#39;change&#39;],
      setup(props, { emit }) {
        emit(&#39;change&#39;) //类型检查 / 自动补全
      }
    })

    is the ref() annotation type

    Default derivation type

    ref will automatically derive its type based on the value during initialization:

    import { ref } from &#39;vue&#39;
     
    // 推导出的类型:Ref<number>
     
    const year = ref(2022)
     
    // TS Error: Type &#39;string&#39; is not assignable to type &#39;number&#39;.
    year.value = &#39;2022&#39;

    Specify the type through the interface

    Sometimes we may want to specify a more complex type for the value in ref. You can use the Ref interface:

    import { ref } from &#39;vue&#39;
    import type { Ref } from &#39;vue&#39;
     
    const year: Ref<string | number> = ref(2022)
    year.value = 2022 //成功

    Specify the type through generics

    Or, when calling ref () to override the default derivation behavior:

    // 得到的类型:Ref<string | number>
    const year = ref<string | number>(&#39;2022&#39;)
    year.value = 2022 //成功

    If you specify a generic parameter but do not give an initial value, the final result will be a value containing undefined Union type:

    // 推导得到的类型:Ref<number | undefined>
    const n = ref<number>()

    is the annotation type for reactive()

    Default derivation type

    reactive() will also implicitly derive the type from its parameters:

    import { reactive } from &#39;vue&#39;
     
    //推导得到的类型:{ title: string }
    const book = reactive({ title: &#39;Vue 3 指引&#39;})

    Specify the type through the interface

    To explicitly specify the type of a reactive variable, we can use the interface:

    import { reactive } from &#39;vue&#39;
     
    interface Book {
      title: string
      year?: number
    }
     
    const book: Book = reactive({ title: &#39;Vue 3 指引&#39; })

    Annotate the type for computed()

    Default derivation Type

    computed() will automatically deduce the type from the return value of its calculation function:

    import { ref, computed } from &#39;vue&#39;
    const count = ref(0)
     
    // 推导得到的类型:ComputedRef<number>
    const double = computed(() => count.value * 2)
     
    // TS Error: Property &#39;split&#39; does not exist on type &#39;number&#39;
    const result = double.value.split(&#39;&#39;)

    Specify the type through generics

    const double = component<number>(() => {
      // 若返回值不是 number 类型则会报错
    })

    Annotate the type for the event processing function

    When processing native DOM events, the parameters of the event processing function should be correctly marked with types, such as:

    <script srtup lang="ts">
    function handleChange(event) {
      // `event` 隐式地标注为 `any`类型
      console.log(event.target.value)
    }
    </script>
     
    <template>
      <input type="text" @change="handleChange" />
    </template>

    When there is no type marking, the event parameter will automatically be recognized as any type. This will also raise a TS error if "strict": true or "noImplicitAny": true is configured in tsconfig.json. Therefore, it is recommended to explicitly annotate the types of event handler function parameters. Additionally, you may need to explicitly cast the properties on the event:

    function handleChange(event: Event) {
      console.log((event.target as HTMLInputElement).value)
    }

    Annotate the type for provide / inject

    provide and inject will usually run in different components. To correctly mark the type of injected values, Vue provides an Injectionkey interface, which is a generic type inherited from Symbol and can be used to synchronize the type of injected values ​​between providers and consumers:

    import { provide, inject } from &#39;vue&#39;
    import type { Injectiokey } from &#39;vue&#39;
     
    const key = Symbol() as Injectionkey<string>
    provide(key,&#39;foo&#39;) // 若提供的是非字符串值会导致错误
     
    const foo = inject(key) // foo 的类型: string | undefined

    It is recommended to put the injected key type in a separate file so that it can be imported by multiple components.

    When using a string to inject key, the type of the injected value is unknown, and the declaration needs to be displayed through generic parameters:

    const foo = inject<string>(&#39;key&#39;) // 类型:string | undefined

    由于提供者在运行时可能没有提供这个值,因此请注意注入的值可能仍然是未定义的。移除 undefined 类型的方法是提供一个默认值

    const foo = inject<string>(&#39;foo&#39;, &#39;bar&#39;) // 类型:string

    如果你确定该值始终被提供,则还可以强制转换该值:

    const foo = inject(&#39;foo&#39;) as string

    为 dom 模板引用标注类型

    模板 ref 需要通过一个显式指定的泛型参数和一个初始值 null 来创建:

    <script setup lang="ts">
    import { ref, onMounted } from &#39;vue&#39;
    const el = ref<HTMLInputElement | null>(null)
     
    onMounted(() => {
      el.value?.focus()
    })
    </script>
     
    <template>
      <input ref="el" />
    </template>

    为了严格的类型安全,请使用可选链或类型守卫来访问 el.value。这是因为直到组件被挂载前,这个 ref 的值都是初始的 null,并且 v-if 将引用的元素卸载时也会被设置为 null。

    为组件模板引用标注类型

    有时候,我们需要为一个子组件添加一个模板引用(template reference),以便可以调用它公开的方法。举个例子,我们有一个 MyModal 子组件,其中包含一个用于打开模态框的方法:

    <script setup lang="ts">
    import { ref } from &#39;vue&#39;
     
    const isContentShown = ref(false)
    const open = () => (isContentShow.value = true)
     
    defineExpose({
      open
    })
    </script>

    为了获取 MyModal 的类型,我们首先需要通过 typeof 得到其类型,再使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类型:

    <script>
    import MyModal from &#39;./MyModal.vue&#39;
     
    const modal = ref<InstanceType<typeof MyModal > | null>(null)
    const openModal = () => {
      modal.value?.open()
    }
    </script>

    The above is the detailed content of How to solve the problem of vue3 getting ref instance combined with ts InstanceType. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete