首頁  >  文章  >  web前端  >  vue3取得ref實例結合ts的InstanceType問題怎麼解決

vue3取得ref實例結合ts的InstanceType問題怎麼解決

WBOY
WBOY轉載
2023-05-20 22:59:321692瀏覽

    vue3取得ref實例結合ts的InstanceType

    有時候我們範本引用,但是在使用的時候,ts提示卻不行,沒有提示元件透過defineExpose暴露的方法名稱,雖然這不是很影響,但是可以解決還是可以解決下~

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

    然後我們在父級使用,輸入完成MyModalRef.value會發現沒有sayHello這個函數提示,所以這個時候我們就需要使用InstanceType 工具類型來取得其實例類型

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

    vue3取得ref實例結合ts的InstanceType問題怎麼解決

    #使用InstanceType 工具類型來取得其實例類型:

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

    父級使用

    <!-- 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>

    貌似依舊沒有提示使用InstanceType在提示的時候,然後輸入錯誤內容也沒有在編譯前進行報錯…,不過vue官方這樣子說了,那就聽他的吧(其實我一般不用,不過也學到了)

    @vue官方API為組件模板引用標註類型

    如何為vue3組件標註TS類型

    Vue3和TS絕對是在今年最受歡迎的前端技術之列。許多公司正在使用 Vue3 TS Vite 組合來開發新專案。以下是重寫的句子:分享在Vue3元件中如何使用Composition-Api結合TS類型。

    為props 標註類型

    使用

    當使用

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

    這稱為運行時聲明,因為傳遞給defineProps() 的參數會作為運行時的props 選項使用。

    第二種方式,透過泛型參數來定義props 的類型,這種方式更直接:

    <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>
    */

    編譯器會嘗試推導類型參數並產生對應的執行時間選項,這種方法被稱為基於類型的聲明。這種方法的缺點在於無法定義props預設值的能力已經喪失。使用 withDefaults 編譯器可以解決這個問題

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

    上面程式碼會被編譯為等價的執行時間 props 的 default 選項。

    如果沒有使用

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

    為emits 標註類型

    使用

    <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>

    我們可以看到,基於類型聲明可以使我們對所觸發事件的類型進行更細粒度的控制。

    若沒有使用

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

    為ref() 標註類型

    預設推導類型

    #ref 會根據初始化時的值自動推導其類型:

    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;

    透過介面指定類型

    有時我們可能想要為ref 內的值指定一個更複雜的類型,可以透過使用Ref 這個介面:

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

    透過泛型指定類型

    #或者,在呼叫ref () 時傳入一個泛型參數,來覆寫預設的推導行為:

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

    如果你指定了一個泛型參數但沒有給出初始值,那麼最後得到的就將是一個包含undefined 的聯合類型:

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

    為reactive() 標註類型

    預設推導類型

    reactive() 也會隱含地從它的參數推導出類型:

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

    透過介面指定類型

    要顯示地指定一個reactive 變數的類型,我們可以使用介面:

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

    為computed() 標註類型

    #預設推導類型

    computed() 會自動從其計算函數地傳回值上推導出類型:

    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;)

    透過泛型指定類型

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

    為事件處理函數標註類型

    在處理原生DOM事件時,應該給事件處理函數的參數正確地標註類型,如:

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

    當沒有型別標註時,這個event參數會自動被辨識為任意型別。這也會在 tsconfig.json 中配置了 "strict": true 或 "noImplicitAny": true 時報出一個 TS 錯誤。因此,建議明確地為事件處理函數地參數標註類型。此外,你可能需要明確地強制轉換 event 上地屬性:

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

    為 provide / inject 標註類型

    provide 和 inject 通常會在不同的元件中運行。要正確地為注入的值標記類型,Vue提供了一個Injectionkey 接口,它是一個繼承自Symbol 的泛型類型,可以用來在提供者和消費者之間同步注入值的類型:

    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

    建議將注入key的類型放在一個單獨的檔案中,這樣它就可以被多個元件導入。

    當使用字串注入 key 時,注入值的類型是 unknown,需要透過泛型參數顯示宣告:

    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>

    以上是vue3取得ref實例結合ts的InstanceType問題怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除