Typescript中的Angular:如何将泛型类型传递给函数 [英] Angular in Typescript: how to pass generic Type to function

查看:1290
本文介绍了Typescript中的Angular:如何将泛型类型传递给函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Typescript编写Angular 5单元测试,我有一个函数将查询DOM并返回 MyComponent 类的实例(如果找到):



pre $函数getMyComponent(hostFixture:ComponentFixture< any>):MyComponent {
const debugElement = hostFixture.debugElement.query(By.directive为MyComponent));

return(debugElement&&&debugElement.componentInstance)||空值;
}

这完美无瑕。现在我想概括一下这个函数,以便它可以根据需要查询任何类型。我认为这可以通过泛型类型来完成,函数的调用方式如下所示:

  const实例:MyComponent = getDirective< MyComponent>(夹具); 

虽然我无法使用它,这里是破碎的函数:

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

return(debugElement&&&debugElement.componentInstance)||空值;

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


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

这里的正确语法是什么?我调用的Angular函数 - By.directive() - 接受一个类型的参数< any> 记录在这里

Type< T> 是一个糟糕的API。你是其中一个被其坦率不负责任的命名*误导的人之一。 类型< T> 确实意味着可构造。这是您可以通过 new 调用的值的类型。



By。指令取得不是类型。该值的类型是可以用 new 调用的东西,可以构造的东西。这意味着一个类或函数。



然而,您可以写出您想要的函数。


$

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

返回debugElement&& debugElement.componentInstance ||不确定的;
}

然后像这样称呼

  const instance = getDirective(fixture,MyComponent); 

备注:

TypeScript类型纯粹是设计时间结构。该语言的整个类型系统经过精心设计,在转换过程中完全擦除,特别是对程序的运行时行为没有影响。


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



这是特别重要的,因为类型 Type< T> 通常被认为是一个类的值,很多人已经在TypeScript和vanilla JavaScript中混淆了类的类型。

Angular希望这些概念这是希望 JavaScript中的类是类似于许多其他语言的类型,但它们根本就不是。



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



有趣的是,Angular团队设计了自己的编程语言,专门称为@Script用于Angular 2的开发。@Script是JavaScript和TypeScript的衍生产品,它通过添加某种程度的类型实例来避免使用装饰器 Annotations 特性。他们在2014年晚些时候放弃了这种语言,而选择使用TypeScript。



不过,我仍然认为,启发@Script的理念仍然影响Angular。 b $ b

Using Typescript to write an Angular 5 unit tests, I have a function that will query the DOM and return an instance of the MyComponent class if found:

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

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

This works flawlessly. Now I'd like to generalize the function so that it could query any Type on demand. I figured this could be done with generic typesThe function would be called like so:

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

I can't get it working though; Here is the broken function:

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

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

The first line within the function throws the error:

TS2693: 'T' only refers to a type, but is being used as a value here

What is the right syntax here? The Angular function I'm calling -- By.directive() -- takes an argument of type Type<any>, and is documented here

解决方案

Angular's Type<T> is a bad API. You are one of many who has been mislead by its frankly irresponsible naming*. Type<T> really means Constructable. It is the type of a value that you can call with new.

By.directive takes a value not a type. The type of that value is something which can be called with new, something that can be constructed. This means a class or a function.

However, you can write the function you wish to.

Here is how I would write it.

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;
}

Then call it like this

const instance = getDirective(fixture, MyComponent);

Remarks:

TypeScript types are purely design time constructs. The language's entire type system was carefully designed to be fully erased during transpilation and in particular to have no impact on the runtime behavior of programs.

Why do I say that the name Type<T> is irresponsible? Because thousands of programmers are learning TypeScript for the first time in the context of Angular. By naming a type Type, they have made things very easy to misunderstand.

This is especially significant because the type Type<T> is usually ascribed to a value that is a class and many people already confuse types with classes in TypeScript and in vanilla JavaScript as well.

Angular wants these concepts to be conflated, it wishes that classes in JavaScript were types like they are in many other languages but they simply are not.

Given the nature of TypeScript, which provides design time only types, this leads to serious confusion.

It is interesting to note that the Angular team designed their own programming language, called @Script specifically for the development of Angular 2. @Script was a derivative of JavaScript and TypeScript that distinguished itself by adding some degree of type reification while eschewing Decorators for a then competing Annotations feature. They abandoned this language late in 2014, opting to use TypeScript instead.

Still I sometimes think that the same philosophy that inspired @Script still influences Angular.

这篇关于Typescript中的Angular:如何将泛型类型传递给函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆