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
相关产品推荐
相关产品推荐

