typescript - 是否可以为方法装饰器选项提供类型安全
问题描述
我决定编写一些实用程序装饰器,例如memoize
, rateLimiter
。我想在没有不必要的样板代码的情况下实现尽可能多的类型安全。
是否可以在没有手动指定泛型的情况下确保装饰器中的完整类型安全?
type GET_FUNCTION_SIGNATURE<
T extends TypedPropertyDescriptor<any>
> = T extends TypedPropertyDescriptor<infer U> ? U : never;
interface ITestDecoratorOptions<DECORATED_FUNCTION_ARGUMENTS_TYPE, DECORATED_FUNCTION_RETURN_TYPE> {
getKeyFromArgs: (args: DECORATED_FUNCTION_ARGUMENTS_TYPE) => string;
getDefaultValue: (args: DECORATED_FUNCTION_ARGUMENTS_TYPE) => DECORATED_FUNCTION_RETURN_TYPE;
}
const testDecorator = <TYPED_PROPERTY_DESCRIPTOR extends TypedPropertyDescriptor<any>>(
options: ITestDecoratorOptions<
Parameters<GET_FUNCTION_SIGNATURE<TYPED_PROPERTY_DESCRIPTOR>>,
ReturnType<GET_FUNCTION_SIGNATURE<TYPED_PROPERTY_DESCRIPTOR>>
>
) => {
return (
target: Object,
key: string,
descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor
): TYPED_PROPERTY_DESCRIPTOR => {
return null as any;
};
};
class Test {
// \/ Is it possible to remove that generic and keep full type safety here?
@testDecorator<TypedPropertyDescriptor<(a: number, b: string) => boolean>>({
getKeyFromArgs: args => {
// number string
return args[0].toString() + args[1]; // full type checking
},
getDefaultValue: args => {
// full type checking: on args(number, string) and return type(boolean)
if (args[0] === 1) {
return true;
}
return false;
}
})
public someMethod(a: number, b: string): boolean {
return true;
}
}
解决方案
这是 TypeScript 中的一个已知问题,没有明显的解决方案(除了手动指定泛型类型参数)。
正如@DanielRosenwasser在此评论中所解释的那样,实现这一点的问题是使用装饰器就像调用咖喱函数一样,您想要的通用推理类型如下:
declare let f: <T>(callback: (x: T) => void) => (y: T) => void;
f(x => x.a)({ a: 100 }); // error!
// ~ <-- T is inferred as {} or unknown,
这不起作用,因为 TypeScript 在函数f
的回调参数上调用函数时会推断泛型类型,并且不会等到返回的函数本身被调用。因此,当T
类型实际上是编译器时,为时已晚,并且已经无法正确推断。
除了继续手动指定参数之外,我不知道我是否有任何建议,如果您认为它比提到的其他内容更引人注目,可能会在 TypeScript 中解决该问题并给出或描述您的用例。祝你好运!
推荐阅读
- bash - 可以在 Bash 函数中本地更改 IFS 吗?
- sql-server - 一个 sql server 可以处理多少个 SQL 作业?
- sql-server - 正则表达式 MS SQL。如何在选择中使用。
- java - 运行spring boot build:创建类路径中定义的名称为“entityManagerFactory”的bean时出错
- go - 将参数作为 bytes32 传递给 Solidity 智能合约
- redux - TypeError: Object(...) is not a function (redux)
- templates - 在 helm 图表中附加 yaml 锚点
- javascript - handel 从 dropbix-api (nodejs 和 express) 返回的对象
- java - 空白的最终字段 conn 可能尚未在非最终成员上初始化
- linux - 验证多个目录存在于其相应的分支上