我正在使用一些代码,这些代码解析属性值的通用类型并且不允许提供错误的值。但是,当我从 TValue
更改为 (t: TValue) => TValue
时,类型 TValue
不会进一步解析。现在是未知的 {}
类型,而不是 number
更多
没有功能的示例。工作顺利
type ProtoOf<T> = Pick<T, keyof T>;
function decorate<TValue>(value: TValue) {
return <T extends { [KA in TKey]: TValue }, TKey extends keyof T>(
proto: ProtoOf<T> & { [P in TKey]: TValue },
propertyKey: TKey
) => {};
}
class Foo {
// TS error: none
// Result: EXPECTED
@decorate(1) bar: number = 1;
// TS Error:
// Types of property 'wrongBar' are incompatible
// Type 'number' is not assignable to type 'string'
// Result: EXPECTED
@decorate('') wrongBar: number = 1;
}
带有函数的示例。没有按预期工作
type ProtoOf<T> = Pick<T, keyof T>;
function decorate<TValue>(getValue: (t: TValue) => TValue) {
return <T extends { [KA in TKey]: TValue }, TKey extends keyof T>(
proto: ProtoOf<T> & { [P in TKey]: TValue },
propertyKey: TKey
) => {};
}
class Foo {
// TS Error: Operator '+' cannot be applied to types '{}' and '1'
// Result: NOT EXPECTED: because we can assign `number` to `number`
@decorate(v => v + 1) bar: number = 1;
// TS error: none
// Result: NOT EXPECTED: we should have error, we cannot assign `string` to `number`
@decorate(v => v + '') wrongBar: number = 1;
}
在具有函数的示例中,我期望 TValue
等于 number
,就像在没有函数的示例中一样
最佳答案
这是一个known issue ,正如您从 GitHub 评论中了解到的那样。总结如下:
目前,类型推断并不能按照您希望的方式工作,因为编译器将原始类型视为等同于如下内容:
const barDeco = decorate(v => v + 1); // error
barDeco(Foo.prototype, "bar");
const wrongBarDeco = decorate(v => v + '');
wrongBarDeco(Foo.prototype, "wrongBar");
并且 barDeco
和 wrongBarDeco
中对 decorate()
的调用没有足够的类型信息供编译器推断泛型类型,因此被推断为 {}
,导致很多悲伤。装饰器基本上是一个柯里化(Currying)函数 f(x)(y)
,要解决这个问题,编译器必须从 的类型推断
,这是一种新的上下文类型。也许装饰器可以针对这种推断进行特殊处理;一般来说,使用柯里化(Currying)函数来做到这一点可能是一个巨大的突破性改变。f
的类型y
目前处理此问题的唯一方法是在调用装饰器时手动指定通用参数,如下所示
class Foo {
@decorate<number>(v => v + 1) bar: number = 1; // okay
@decorate<number>(v => v + '') wrongBar: number = 1; // error
}
或者手动注释您的回调,如
class Foo {
@decorate((v: number) => v + 1) bar: number = 1; // okay
@decorate((v: number) => v + '') wrongBar: number = 1; // error
}
这些解决方法不是最佳的,但它们确实有效,因此您可以通过某种方式处理问题,除非且直到 Microsoft/TypeScript#2607已解决。有很多很多悬而未决的问题,所以我不希望在这一问题上看到太多进展。如果更多的人关注这个问题并给它一个👍并描述令人信服的用例以及解决方法不足的令人信服的原因,那么这种可能性就会增加。既然你已经做到了这一点,我认为你没有什么可做的,只能继续前进。如果 future 的读者关心这个问题,他们可以在 GitHub 中查看该问题并做出贡献。
抱歉,没有更好的答案给您。祝你好运!
关于typescript - 如何从装饰器中的装饰属性解析属性值的通用类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55409151/