在Typescript的泛型中使用带有strictFunctionTypes的枚举

时间:2018-08-16 20:51:09

标签: function typescript generics enums

我有以下代码(TS playground link):

const enum Enum { A, B, C }

interface Args {
  e: Enum.A;
}

interface GenericClass<A> {
  new (args: A) : void;
}

class TestClass {
  constructor(args: Args) {}
}

function func<A>(C: GenericClass<A>, args: A) {
  return new C(args);
}

func(TestClass, { e: Enum.A });

最后一行[1]在启用strictFunctionTypes的情况下引发错误:

Argument of type 'typeof TestClass' is not assignable to parameter of type 'GenericClass<{ e: Enum; }>'.
  Types of parameters 'args' and 'args' are incompatible.
    Type '{ e: Enum; }' is not assignable to type 'Args'.
      Types of property 'e' are incompatible.
        Type 'Enum' is not assignable to type 'Enum.A'.

这很奇怪,因为我接受精确的枚举值Enum.A,并且将完全相同的值Enum.A传递给函数。

我知道我可以使用类型转换{ e: <Enum.A>Enum.A },但对我来说看起来很奇怪。这是一种无需类型转换即可解决此问题的方法吗?

1 个答案:

答案 0 :(得分:2)

我不是100%知道为什么会发生这种情况,但是我相信,在推断A时,编译器将同时考虑出现A的两个地方,并确定最可能的类型是{ e:Enum}基于以下事实:对象文字通常不会为其字段推断文字类型。推断之后,将看到在严格功能下,类型与类不兼容。根据这种理论,如果我们降低第二个推理站点的优先级,则应该为A获得正确的类型。我们可以使用交集类型A&{}来做到这一点(我不确定我确切地读到了什么,但这是在github问题中,并且编译器团队的一位成员提到降低推理优先级的这种方式可能会起作用在可预见的未来)。

再次多数是有根据的猜测,但解决方案有效:

const enum Enum { A, B, C }

interface Args {
  e: Enum.A;
}

interface GenericClass<A> {
  new (args: A) : void;
}

class TestClass {
  constructor(args: Args) {}
}


function func<A>(C: GenericClass<A>, args: A & {}) {
  return new C(args);
}

func(TestClass, { e: Enum.A });

playground link