简体   繁体   English

新的EventEmitter()与新的EventEmitter <Something> ()

[英]new EventEmitter() vs new EventEmitter<Something>()

Let's say I have this code: 假设我有以下代码:

export class ProductsListComponent {
  @Output() onProductSelected: EventEmitter<Product>;

  constructor() { 
    this.onProductSelected = new EventEmitter();
  }
}

This is some example of EventEmitter usage. 这是EventEmitter用法的一些示例。 I don't understand why first we declare onProductSelect explicitly stating that it is EventEmitter that carries Product instance, and then we instantiate it with just new EventEmitter() . 我不明白为什么我们首先明确声明onProductSelect声明它是携带Product实例的EventEmitter ,然后仅使用new EventEmitter()实例化它。 Why not new EventEmitter<Product>() ? 为什么不new EventEmitter<Product>()

I think that in C# I would have to go with the second way, because otherwise it wouldn't compile if EventEmitter was generic. 我认为在C#中,我将不得不采用第二种方式,因为如果EventEmitter是通用的,否则它将无法编译。 Why doesn't TypeScript require that? 为什么TypeScript不要求?


//EDIT: //编辑:

Further clarification fo my question. 我的问题需要进一步澄清。 What's the difference between: 之间有什么区别:

@Output() onProductSelected: EventEmitter<Product>;
this.onProductSelected = new EventEmitter();

and

@Output() onProductSelected: EventEmitter;
this.onProductSelected = new EventEmitter();

As explained in documentation chapter , type argument inference occurs when type isn't specified for generic class or function. 文档章节所述 ,当未为通用类或函数指定type时,将发生类型实参推断。

A function can infer T type from its argument or return types, and a class can infer T type from constructor argument or return types: 函数可以推断T从它的参数类型或返回类型,而一个类可以推断T从构造器参数类型或返回类型:

function foo<T>(v: T) { return v }
foo(1); // T inferred to number

class Foo<T> {
  constructor(v: T) {}
}
new Foo(1); // T inferred to number

If there's nothing to infer, T is inferred to empty object {} for some reason : 如果没有什么可以推断的,则出于某种原因T被推断为空对象{}

class Foo<T> {
  foo(v: T) {}
}

new Foo().foo(1); // T inferred to {}

In order to avoid inference to {} , default type can be provided: 为了避免推论{} ,可以提供默认类型:

class Foo<T = string> {
  foo(v: T) {}
}

new Foo().foo(1); // type error

If generic class or function isn't supposed to be used with default type, some impossible type can be specified: 如果不应将通用类或函数与默认类型一起使用,则可以指定一些不可能的类型:

class Foo<T = never> {
  foo(v: T) {}
}

new Foo(); // no type error, T isn't involved
new Foo().foo(<any>1); // type error

Since EventEmitter generic class has no default type specified, the latter is inferred to {} . 由于EventEmitter泛型类未指定默认类型,因此后者被推断为{} There usually won't be problems with that, because emit is the only method that is affected by generic type . 通常不会有任何问题,因为emit唯一受泛型类型影响的方法 Since all non-nully types can be coerced to object type, this usually won't cause type errors - as long as nully types are ignored. 由于所有非null类型都可以强制转换为对象类型,因此只要忽略null类型,通常就不会导致类型错误。

strictNullChecks compiler option will be a problem for EventEmitter with default type and nully values: 对于使用默认类型和空值的EventEmitterstrictNullChecks编译器选项将是一个问题:

const ee = new EventEmitter();
ee.emit(null); // type error

So for all-round EventEmitter it shouldn't rely on default type and be instantiated as: 因此,对于全方位EventEmitter它不应依赖默认类型,而应实例化为:

const ee = new EventEmitter<any>();

EventEmitter() will work the same as EventEmitter<any>() . EventEmitter()EventEmitter<any>() If you draw this in HTML on the selector of ProductsListComponents , then you can listen to onProductSelected event and assign an action like onSelected when that happens. 如果您在HTML上在ProductsListComponents的选择器上绘制此内容,则可以侦听onProductSelected事件,并在发生这种情况时分配类似onSelected的操作。 By default you'll get a new EventEmitter<any>() , and defining a variable of any type is the generic approach in Typescript. 默认情况下,您将获得一个新的EventEmitter<any>() ,并且定义any类型的变量都是Typescript中的通用方法。

<product-list (onProductSelected)="onSelected($event)"> </product-list>

So every time in your child you call 所以每次你的孩子你打电话

this.onProductSelected.emit("hello");
this.onProductSelected.emit(1);

Parent's function onSelected($event) will get called and you can do anything with that data. Parent的函数onSelected($event)将被调用,您可以使用该数据执行任何操作。


If you're only expecting one type of data to get outputted to the parent so it can further handle it, then you'd want to stick to a specific data type. 如果您只希望将一种类型的数据输出到父级以便可以进一步处理它,那么您就希望坚持使用一种特定的数据类型。

onProductSelected: Product = new EventEmitter<Product>(); 
products: Product[];

then somewhere in your code you can trigger to emit 然后您可以在代码中的某处触发发出

this.onProductSelected.emit(this.products[1]);

Added an example in stackblitz 在stackblitz中添加了一个示例

Regarding your updated question 关于您更新的问题

@Output() onProductSelected: EventEmitter; is an error, because here you're declaring a type (after : , before = ), as oppose to defining a type (after = ), when you declare it as an EventEmitter you do need an argument <type> 是一个错误,因为在这里您声明一个类型(在:之后, =之前),与定义一个类型(在=之后)相反,当您将其声明为EventEmitter时,确实需要一个参数<type>

If you declare the type of EventEmitter, then the compiler will make sure you don't emit anything other than Product type, or what type you declare it to be. 如果声明了EventEmitter的类型,则编译器将确保您不发出除Product类型或声明为哪种类型以外的任何东西。

@Output() onProductSelected: EventEmitter<Product>;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM