如何在TypeScript中实现适配默认/指定类型的泛型动态函数
解决带默认类型的泛型函数字典类型适配问题
问题分析
你定义的SocketFunctions将每个成员标注为调用时确定类型的泛型函数(<T = SocketType>(data: T) => void),这意味着函数必须能接受任意T类型的参数。但你在实现function_one时访问了value.coolType,这要求参数必须包含coolType属性,和泛型函数“兼容任意类型”的要求矛盾,因此触发编译错误。
以下是三种符合需求的解决方案,可根据实际场景选择:
方案一:显式绑定函数的默认泛型参数
如果函数仅需处理默认的SocketType类型,可在定义函数时显式指定泛型参数的默认值,让TypeScript明确参数类型为SocketType,从而正常访问其属性:
type SocketType = { coolType: string, foo: number, bar: number[] } type AnotherSocketType = { ipsum: () => void, blabla: string, towMater: number } type SocketFunctions = { [key: string]: <T = SocketType>(data: T) => void } // 显式指定泛型参数的默认值为SocketType const firstFunctionsList: SocketFunctions = { function_one: <T = SocketType>(value: T) => { const data = value.coolType; // 编译通过,可正常访问属性 // 其他业务逻辑 } } const secondFunctionsList: SocketFunctions = {}
调用示例
const firstData: SocketType = { coolType: "this is a cool string", foo: 8273, bar: [1, 2, 3, 4] } const secondData: AnotherSocketType = { ipsum: () => {}, blabla: "The lazy fox jumps over bla bla bla", towMater: 1522 } const test = 'someFunctionName'; const firstFunc = firstFunctionsList[test]; const secondFunc = secondFunctionsList[test]; // 无需指定类型,自动使用默认的SocketType if (typeof firstFunc === 'function') firstFunc(firstData); // 显式指定类型,使用AnotherSocketType if (typeof secondFunc === 'function') secondFunc<AnotherSocketType>(secondData);
方案二:使用联合类型兼容多种函数类型
如果希望字典同时支持“仅处理默认类型的普通函数”和“可指定任意类型的泛型函数”,可将SocketFunctions的成员类型定义为联合类型:
type SocketType = { coolType: string, foo: number, bar: number[] } type AnotherSocketType = { ipsum: () => void, blabla: string, towMater: number } // 联合类型:要么是处理SocketType的普通函数,要么是带默认类型的泛型函数 type SocketFunctions = { [key: string]: ((data: SocketType) => void) | (<T = SocketType>(data: T) => void) } // 定义仅处理SocketType的普通函数,无需泛型 const firstFunctionsList: SocketFunctions = { function_one: (value) => { const data = value.coolType; // 编译通过,类型自动推断为SocketType // 其他业务逻辑 } } // 定义泛型函数,可处理任意指定类型 const secondFunctionsList: SocketFunctions = { function_two: <T>(value: T) => { // 编写兼容任意类型的通用逻辑,比如打印参数 console.log(value); } }
调用示例
const firstData: SocketType = { coolType: "this is a cool string", foo: 8273, bar: [1, 2, 3, 4] } const secondData: AnotherSocketType = { ipsum: () => {}, blabla: "The lazy fox jumps over bla bla bla", towMater: 1522 } const firstFunc = firstFunctionsList['function_one']; const secondFunc = secondFunctionsList['function_two']; if (typeof firstFunc === 'function') firstFunc(firstData); if (typeof secondFunc === 'function') secondFunc<AnotherSocketType>(secondData);
方案三:泛型字典(绑定单一类型)
如果每个字典仅处理一种固定类型,可将SocketFunctions定义为泛型类型,让整个字典的函数都绑定到指定类型:
type SocketType = { coolType: string, foo: number, bar: number[] } type AnotherSocketType = { ipsum: () => void, blabla: string, towMater: number } // 泛型字典,默认类型为SocketType type SocketFunctions<T = SocketType> = { [key: string]: (data: T) => void } // 绑定SocketType的字典 const firstFunctionsList: SocketFunctions = { function_one: (value) => { const data = value.coolType; // 编译通过 // 其他业务逻辑 } } // 绑定AnotherSocketType的字典 const secondFunctionsList: SocketFunctions<AnotherSocketType> = { function_two: (value) => { value.ipsum(); // 编译通过,可访问AnotherSocketType的属性 // 其他业务逻辑 } }
调用示例
const firstData: SocketType = { coolType: "this is a cool string", foo: 8273, bar: [1, 2, 3, 4] } const secondData: AnotherSocketType = { ipsum: () => {}, blabla: "The lazy fox jumps over bla bla bla", towMater: 1522 } const firstFunc = firstFunctionsList['function_one']; const secondFunc = secondFunctionsList['function_two']; // 无需指定类型,字典已绑定对应类型 if (typeof firstFunc === 'function') firstFunc(firstData); if (typeof secondFunc === 'function') secondFunc(secondData);
内容的提问来源于stack exchange,提问作者Erick Crus
相关产品推荐
相关产品推荐

