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

时间:2019-03-29 01:14:19

标签: 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,在没有函数的示例中,

1 个答案:

答案 0 :(得分:1)

这是一个known issue,从GitHub注释中可以看出。在这里总结:

当前,类型推断无法按您希望的方式工作,因为编译器将原始推断等同于以下内容:

const barDeco = decorate(v => v + 1); // error
barDeco(Foo.prototype, "bar");
const wrongBarDeco = decorate(v => v + '');
wrongBarDeco(Foo.prototype, "wrongBar");

并且decorate()barDeco中对wrongBarDeco的调用没有足够的类型信息供编译器推断通用类型,因此被推断为{{1} },导致很多悲伤。装饰器基本上是咖喱函数{},并且要解决此问题,编译器必须从f(x)(y)的类型推断f的类型,这是一种新的上下文类型。也许装饰器可能是特殊情况下的推理。通常,使用咖喱函数来完成此操作可能是一个巨大的突破性变化。

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

y

或手动注释回调,如

class Foo {
  @decorate<number>(v => v + 1) bar: number = 1; // okay
  @decorate<number>(v => v + '') wrongBar: number = 1; // error
}

这些变通办法不是最佳解决方案,但是它们确实有效,因此除非解决Microsoft/TypeScript#2607,否则您有某种处理问题的方法。有很多很多未解决的问题,所以我不希望看到这个问题有太多进展。如果有更多的人去解决这个问题并给出一个解决方案,并描述令人信服的用例和令人信服的原因,那么这种可能性就会增加。既然您已经完成了此操作,那么我认为您没有什么可以做的,而是继续前进。如果将来的读者对此有所关注,则可以在GitHub中查看问题并做出贡献。

对不起,您没有更好的答案。祝你好运!