【问题标题】:Instantiating TypeScript generic class without specifying type实例化 TypeScript 泛型类而不指定类型
【发布时间】:2017-12-13 15:58:12
【问题描述】:

如果我创建一个泛型类

class Generic<T> {
     prop: T;
}

如果没有在类型中指定T,它将不允许我输入内容

// Generic type 'Generic<T>' requires 1 type argument(s).
const val: Generic = new Generic(); 

但是如果我使用类型推断,它不会抱怨,它让我实例化它

const val = new Generic();
// field prop is not of type any, we can't access any properties on it
// val.prop.anything -> Compiler error
// val.prop.toString() -> No error, is it a string?
// val.prop.length -> Compiler error, not a string, just assumes that everything has a toString (based on boxing)

是否指定了此行为?这背后的原因是什么?

背景

Angular2 有一个EventEmitter,它需要事件的参数类型。但是,对于某些事件,您不传递任何参数,在这种情况下,我们一直使用EventEmitter&lt;void&gt;。但是,我只是注意到您可以在不指定类型的情况下定义发射器,new EventEmitter() 可以工作。这种方法的缺点是如果您将参数传递给emitter.emit('something'),编译器不会抱怨。这不是我感兴趣的,只是背景,以便读者了解问题的来源。

游乐场 https://www.typescriptlang.org/play/#src=class%20Generic%3CT%3E%20%7B%0D%0A%20%20%20%20prop%3A%20T%3B%0D%0A%7D%0D%0A%0D%0Aconst%20val%3A%20Generic%20%3D%20new%20Generic()%3B%0D%0A%0D%0Aconst%20val2%20%3D%20new%20Generic()%3B%0D%0A%0D%0Aval2.prop.test%20%3D%201%3B

【问题讨论】:

  • 由于泛型在运行时不可用(它将全部变为纯 Javascript),我可以想象 new Generic() 行是允许的,因为您可以在导入转译库的 Javascript 中使用这一行.简而言之:为了与 Javascript 兼容。
  • 您使用的是哪个版本的打字稿?尝试编译您的代码时出现错误。 Generic type 'Generic&lt;T&gt;' requires 1 type argument(s).
  • @Sebastian 我无法理解你在说什么......有任何链接可以验证你的想法吗?如果允许,那么现在您有一个没有类型的属性,这似乎与 JavaScript 不兼容,因为如果您想使用它,您必须将 prop 转换为某种东西?
  • @Duncan 我正在使用在线游乐场,我认为它是最新的?

标签: angular typescript generics


【解决方案1】:

以下两个语句是等价的……

const val: Generic<{}> = new Generic();
const val2 = new Generic();

在第一种情况下,右侧省略的类型参数是从左侧的类型推断出来的。

在第二种情况下,您最终得到一个对象类型,因为无法推断出更具体的类型。

这里的规则是变量的类型必须满足泛型类型参数。当您使用const val: Generic = new Generic(); 时,类型参数不满足 - 您不能要求推断它,因为您已决定对变量进行注释。

所以两种允许的情况是:

  1. 使用类型注释自己指定(整个)类型
  2. 允许编译器推断(整个)类型

要使后面的示例正常工作,您有两个选择。

选项1...如果您真的不想限制类型,请使用动态...

const val2 = new Generic<any>();
val2.prop.test = 1;

或者...选项2...如果您确实想限制类型,请指定它。

const val2 = new Generic<{ test: number }>();
val2.prop.test = 1;

最后,在许多情况下,您不需要指定类型参数,因为它可以根据上下文进行推断。

【讨论】:

  • const val: Generic = new Generic(); ?
  • 他也可以将其默认为any,这样就不必明确指定。 class Generic&lt;T = any&gt; { ... }
  • @JeffMercado 对于我的具体情况,当人们将参数传递给发出调用 emitter.emit('what') // should throw error 时,这将停止抛出错误
猜你喜欢
  • 1970-01-01
  • 2020-06-11
  • 2013-10-03
  • 2011-04-02
  • 2013-09-18
  • 1970-01-01
  • 2020-01-10
相关资源
最近更新 更多