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

Vue中TypeScript如何根据入参为useFetch变量条件断言类型?

解决Vue useFetch组合式函数的TypeScript类型推断问题

你需要实现一个Vue的useFetch组合式函数,要求:

  • 传入defaultValue: T时,返回的fetchedData类型为Ref<T>
  • 未传入defaultValue时,fetchedData类型为Ref<T | undefined>
    但当前即使传入默认值,TypeScript仍提示fetchedData.value可能为undefined。

方法1:使用函数重载(推荐)

函数重载可以让TypeScript根据传入的参数类型自动匹配对应返回类型,完美满足需求。

修改后的useFetch代码:

import type { Ref } from "vue";
import { ref } from "vue";

// 重载签名1:传入defaultValue时,返回Ref<T>
export default function useFetch<T>(options: { defaultValue: T }): { fetchedData: Ref<T> };
// 重载签名2:不传入defaultValue时,返回Ref<T | undefined>
export default function useFetch<T>(): { fetchedData: Ref<T | undefined> };
// 函数实现(兼容两个重载签名)
export default function useFetch<T>({
    defaultValue,
}: {
    defaultValue?: T;
} = {}) {
    let temp: Ref<T> | Ref<T | undefined>;
    if (defaultValue !== undefined) {
        temp = ref(defaultValue) as Ref<T>;
    } else {
        temp = ref() as Ref<T | undefined>;
    }

    const fetchedData = temp;

    // 这里添加数据请求逻辑,例如:
    // fetch('/api/data').then(res => res.json()).then(data => {
    //   fetchedData.value = data;
    // });

    return {
        fetchedData,
    };
}

组件使用效果

import useFetch from "@composables/useFetch";
import type { ICustomInterface } from "@types";

// 传入defaultValue,TypeScript自动推断fetchedData为Ref<ICustomInterface[]>
const { fetchedData } = useFetch<ICustomInterface[]>({ defaultValue: [] });
fetchedData.value[0]; // 不再提示"possibly undefined"

方法2:使用条件泛型

如果你希望通过泛型参数显式控制类型,可以用条件泛型实现,但需要手动指定额外的泛型参数:

import type { Ref } from "vue";
import { ref } from "vue";

export default function useFetch<T, HasDefault extends boolean = false>({
    defaultValue,
}: {
    defaultValue?: HasDefault extends true ? T : never;
} = {}) {
    // 根据HasDefault参数决定返回的Ref类型
    type DataRef = HasDefault extends true ? Ref<T> : Ref<T | undefined>;
    let temp: DataRef;

    if (defaultValue !== undefined) {
        temp = ref(defaultValue) as DataRef;
    } else {
        temp = ref() as DataRef;
    }

    const fetchedData = temp;

    // 请求逻辑...

    return {
        fetchedData,
    };
}

组件使用

// 显式指定第二个泛型参数为true,表示传入了默认值
const { fetchedData } = useFetch<ICustomInterface[], true>({ defaultValue: [] });
fetchedData.value[0]; // 无undefined提示

关于as Ref<T>的说明

你提到使用类型断言是为了避免Ref<UnwrapRef<T>>,这是合理的。如果你的T是需要保持原始引用的复杂对象,也可以考虑用shallowRef替代ref,这样无需类型断言就能得到Ref<T>类型:

// 用shallowRef替代ref,无需类型断言
temp = shallowRef(defaultValue); // 类型为Ref<T>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:13:25