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

如何用泛型+条件类型替代TypeScript函数重载?

用泛型+条件类型替代useKeyData函数的重载实现

问题背景

原有useKeyData函数通过重载实现两种行为:

  • 传入keyof SomeObjectType类型参数时,返回string | undefined
  • 无参数时,返回SomeObjectType

尝试改用泛型+条件类型移除重载时,出现类型不匹配错误:类型 SomeObjectType 无法分配给类型 ReturnedValue<T>

原重载实现

type SomeObjectType = { a?: string; b?: string };

// 原有重载实现
export function useKeyData(
  keyName: keyof SomeObjectType,
): string | undefined;
export function useKeyData(): SomeObjectType;

export function useKeyData(
  keyName?: keyof SomeObjectType,
): string | SomeObjectType | undefined {
  const value = { a: 'hello', b: 'hi' } as SomeObjectType;

  const valueToReturn = keyName ? value[keyName] : value;

  return valueToReturn;
}

// 调用示例
const value1 = useKeyData('a'); // value1类型为string | undefined
const value2 = useKeyData(); // value2类型为SomeObjectType

错误的泛型尝试实现

type SomeObjectType = { a?: string; b?: string };

type ReturnedValue<T extends keyof SomeObjectType | undefined> = T extends keyof SomeObjectType
  ? string | undefined
  : SomeObjectType;

export const useKeyData = <T extends keyof SomeObjectType | undefined>(
  keyName?: T,
): ReturnedValue<T> => {
  const value = { a: 'hello', b: 'hi' } as SomeObjectType;

  const valueToReturn = keyName ? value[keyName] : value;

  return valueToReturn; // 报错:类型 SomeObjectType 无法分配给类型 ReturnedValue<T>
};

正确实现方式

问题核心在于TypeScript无法将泛型条件类型ReturnedValue<T>与函数内控制流产生的联合类型自动关联,需要手动断言返回值,同时优化条件类型以更精准匹配属性类型:

type SomeObjectType = { a?: string; b?: string };

// 条件类型直接取对应属性的类型,更精准
type ReturnedValue<T> = T extends keyof SomeObjectType 
  ? SomeObjectType[T] 
  : SomeObjectType;

export function useKeyData<T extends keyof SomeObjectType | void = void>(
  keyName?: T,
): ReturnedValue<T> {
  const value = { a: 'hello', b: 'hi' } as SomeObjectType;
  
  // 手动断言返回值符合条件类型
  return (keyName ? value[keyName] : value) as ReturnedValue<T>;
}

// 调用验证
const value1 = useKeyData('a'); // 类型:string | undefined
const value2 = useKeyData(); // 类型:SomeObjectType

另一种更严谨的实现

如果想避免类型断言,可以通过保留重载类型定义但合并函数体的方式,既满足类型安全又简化实现:

type SomeObjectType = { a?: string; b?: string };

export function useKeyData<T extends keyof SomeObjectType>(keyName: T): SomeObjectType[T];
export function useKeyData(): SomeObjectType;
export function useKeyData(keyName?: keyof SomeObjectType) {
  const value = { a: 'hello', b: 'hi' } as SomeObjectType;
  return keyName ? value[keyName] : value;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:22:20