typescript - 如何从装饰器中的装饰属性解析属性值的通用类型

标签 typescript generics generic-programming typescript-decorator

我正在使用一些代码,这些代码解析属性值的通用类型并且不允许提供错误的值。但是,当我从 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");

并且 barDecowrongBarDeco 中对 decorate() 的调用没有足够的类型信息供编译器推断泛型类型,因此被推断为 {},导致很多悲伤。装饰器基本上是一个柯里化(Currying)函数 f(x)(y),要解决这个问题,编译器必须从 的类型推断 f 的类型y,这是一种新的上下文类型。也许装饰器可以针对这种推断进行特殊处理;一般来说,使用柯里化(Currying)函数来做到这一点可能是一个巨大的突破性改变。

目前处理此问题的唯一方法是在调用装饰器时手动指定通用参数,如下所示

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/

相关文章:

javascript - 返回值未在花药返回有效负载中拾取

swift - “无法推断通用参数 'T'”

C - 通用函数 : swap two items in array

javascript - 使用 findIndex 检查对象数组中是否存在元素数组 - typescript

typescript - 类型 'Key' 不能用于索引类型 'Object'

typescript - 类型 'recaptchaLoaded' .ts(2339) 上不存在属性 'IReCaptchaComposition | undefined'

java - 如何在不需要 @SuppressWarnings 的情况下正确编码此泛型

java - <? 之间的区别扩展 CustomClass> 和 <CustomClass> 通用性

c++ - 通过模板函数调用未知类型的方法

java - Java Generic Type 参数可以扩展另一个 Type 参数和附加的有界类型吗?