如何用泛型+条件类型替代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
相关产品推荐
相关产品推荐

