【问题标题】:Angular in Typescript: how to pass generic Type to functionTypescript 中的 Angular:如何将泛型类型传递给函数
【发布时间】:2018-07-02 19:52:00
【问题描述】:

使用 Typescript 编写 Angular 5 单元测试,我有一个函数可以查询 DOM 并在找到时返回 MyComponent 类的实例:

function getMyComponent(hostFixture: ComponentFixture<any>): MyComponent {
  const debugElement = hostFixture.debugElement.query(By.directive(MyComponent));

  return (debugElement && debugElement.componentInstance) || null;
}

这完美无缺。现在我想概括一下这个函数,以便它可以按需查询任何类型。我想这可以用泛型类型来完成。函数会这样调用:

const instance: MyComponent = getDirective<MyComponent>(fixture);

我无法让它工作;这是损坏的功能:

function getDirective<T>(hostFixture: ComponentFixture<any>): T {
  const debugElement = hostFixture.debugElement.query(By.directive(T));

  return (debugElement && debugElement.componentInstance) || null;
}

函数内的第一行抛出错误:

TS2693:'T' 仅指一种类型,但在此处用作值

这里的正确语法是什么?我正在调用的 Angular 函数 -- By.directive() -- 接受 Type&lt;any&gt; 类型的参数,并且是 documented here

【问题讨论】:

  • Angular 的 Type&lt;T&gt; 是一个糟糕的 API。您是许多被其坦率不负责任的命名误导的人之一。 Type&lt;T&gt; 真正的意思是 Constructable&lt;T&gt;。它是你可以用new调用的值的类型
  • @AluanHaddad 那么这是否意味着我的通用函数需要接受这个 Constructable 作为参数才能工作?我无法从泛型类型T中提取 Constructable?
  • 不,你可能不会。 TypeScript 类型是纯粹的设计时构造。请参阅我的答案,了解如何使其发挥作用。

标签: angular typescript generics


【解决方案1】:

Angular 的 Type&lt;T&gt; 是一个糟糕的 API。您是许多被其坦率不负责任的命名误导的人之一(见评论)。 Type&lt;T&gt; 真正的意思是可构造的。它是您可以使用new 调用的值的类型。

By.directive 采用 value 而不是类型。该值的类型可以用new 调用,可以构造。这意味着一个类或一个函数。

但是,您可以编写您想要的函数。

我会这样写。

function getDirective<T>(
  hostFixture: ComponentFixture<any>, 
  ComponentConstructor: new (...args: any[]) => T
): T {
  const debugElement = hostFixture.debugElement.query(By.directive(ComponentConstructor));

  return debugElement && debugElement.componentInstance || undefined;
}

那就这样称呼吧

const instance = getDirective(fixture, MyComponent);

备注:

TypeScript 类型是纯粹的设计时构造。该语言的整个类型系统经过精心设计,可在编译期间完全擦除,尤其是对程序的运行时行为没有影响。

为什么我说Type&lt;T&gt;这个名字不负责任?因为成千上万的程序员是第一次在 Angular 的上下文中学习 TypeScript。通过命名类型 Type,他们让事情变得很容易被误解。

这尤其重要,因为 Type&lt;T&gt; 类型通常被赋予一个类的值,而且许多人已经将类型与 TypeScript 和原生 JavaScript 中的类混淆了。

Angular 希望将这些概念混为一谈,它希望 JavaScript 中的类与许多其他语言中的类型一样,但事实并非如此。值得注意的是,我更喜欢 Aurelia 等框架也鼓励这种混淆,但是因为它们不尝试强制使用 TypeScript,而且它们允许通过类的属性指定依赖关系(也许具有讽刺意味在方式或 AngularJS 中,混淆的可能性较小。不管怎样,TypeScript 类型、ECMAScript 类和依赖注入都是完全正交的概念。

鉴于 TypeScript 的性质,它只提供设计时类型,这会导致严重的混淆。

有趣的是,Angular 团队设计了他们自己的编程语言,称为 @Script 专门用于 Angular 2 的开发。@Script 是 JavaScript 和 TypeScript 的衍生物,它通过添加某种程度的类型具体化同时避开装饰器 用于当时竞争的 注释 功能。他们在 2014 年底放弃了这种语言,转而使用 TypeScript。

我有时仍然认为启发 @Script 的相同理念仍然影响着 Angular。

【讨论】:

  • 感谢您的扩展答案。当我回到我的办公桌时,我会尝试一下。 +1
猜你喜欢
  • 2018-07-07
  • 2017-07-19
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多