Javascript 如何在编译时在@NgModule中检测不匹配的提供程序? 问题描述

Javascript 如何在编译时在@NgModule中检测不匹配的提供程序? 问题描述,javascript,angular,typescript,dependency-injection,type-safety,Javascript,Angular,Typescript,Dependency Injection,Type Safety,在这种情况下,可以使用注入令牌或抽象类将服务注册到DI容器(请参阅) 然而,这两种技术似乎都没有在编译时通知开发人员应该提供的内容与实际提供的内容之间的意外不匹配。您可以简单地说,我提供了一个IBar的实例,而您实际上提供了一个不满足IBar约束的类Foo 在其他语言(如C#或Java)中,使用不匹配的接口注册服务会立即引发错误,但对于Typescript/Angular,情况似乎并非如此,这为意外的不匹配留下了空间 问题: 当提供程序与类型不匹配时,如何在提供程序中使用类型化标记或抽象类注册服

在这种情况下,可以使用注入令牌或抽象类将服务注册到DI容器(请参阅)

然而,这两种技术似乎都没有在编译时通知开发人员应该提供的内容与实际提供的内容之间的意外不匹配。您可以简单地说,我提供了一个
IBar
的实例,而您实际上提供了一个不满足
IBar
约束的类
Foo

在其他语言(如C#或Java)中,使用不匹配的接口注册服务会立即引发错误,但对于Typescript/Angular,情况似乎并非如此,这为意外的不匹配留下了空间

问题: 当提供程序与类型不匹配时,如何在
提供程序中使用类型化标记或抽象类注册服务时,在编译时引发错误

例子 例如,以下两种情况下的编译都不会出错,但在运行时会引发错误:

场景1–配置期间使用类型化令牌时不匹配:

import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { NgModule, Inject, InjectionToken } from '@angular/core';

interface IBar {
  getBar: () => string;
}

export class Foo {
  getFoo: () => string;
}

@Component({
  selector: 'app-main',
  template: '<h1>Hello world</h1>'
})
export class MyComponent {
  constructor(@Inject(MyToken) bar: IBar) {
    // this will fail since Foo is injected by DI even though the
    // signature says IBar is received
    bar.getBar();
  }
}

export const MyToken = new InjectionToken<IBar>('foo');

@NgModule({
  declarations: [
    MyComponent
  ],
  imports: [
    BrowserModule,
  ],
  providers: [
    // note: we register Foo even though the token is typed with IBar
    // and the service also expects to receive IBar
    { provide: MyToken, useClass: Foo },
  ],
  bootstrap: [
    MyComponent
  ]
})
export class AppModule { }
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { NgModule } from '@angular/core';

abstract class Bar {
  getBar: () => string;
}

class Foo {
  getFoo: () => string;
}

@Component({
  selector: 'app-main',
  template: '<h1>Hello world</h1>'
})
class MyComponent {
  constructor(bar: Bar) {
    // this will fail since Foo is injected by DI even though the
    // signature says IBar is received
    bar.getBar();
  }
}

@NgModule({
  declarations: [
    MyComponent
  ],
  imports: [
    BrowserModule,
  ],
  providers: [
    // note: we register Foo even though the token is typed with IBar
    // and the service also expects to receive IBar
    { provide: Bar, useClass: Foo },
  ],
  bootstrap: [
    MyComponent
  ]
})
export class AppModule { }
从'@angular/platform browser'导入{BrowserModule};
从'@angular/core'导入{Component};
从“@angular/core”导入{NgModule,injection,InjectionToken};
接口IBar{
getBar:()=>字符串;
}
出口类食品{
getFoo:()=>字符串;
}
@组成部分({
选择器:'应用程序主',
模板:“你好,世界”
})
导出类MyComponent{
构造函数(@Inject(MyToken)条:IBar){
//这将失败,因为即使
//签名表明已收到IBar
getBar();
}
}
export const MyToken=new InjectionToken('foo');
@NGD模块({
声明:[
真菌成分
],
进口:[
浏览器模块,
],
供应商:[
//注意:即使令牌是用IBar键入的,我们也会注册Foo
//该服务还希望接收IBar
{provide:MyToken,useClass:Foo},
],
引导:[
真菌成分
]
})
导出类AppModule{}
场景2–配置期间使用抽象类时不匹配:

import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { NgModule, Inject, InjectionToken } from '@angular/core';

interface IBar {
  getBar: () => string;
}

export class Foo {
  getFoo: () => string;
}

@Component({
  selector: 'app-main',
  template: '<h1>Hello world</h1>'
})
export class MyComponent {
  constructor(@Inject(MyToken) bar: IBar) {
    // this will fail since Foo is injected by DI even though the
    // signature says IBar is received
    bar.getBar();
  }
}

export const MyToken = new InjectionToken<IBar>('foo');

@NgModule({
  declarations: [
    MyComponent
  ],
  imports: [
    BrowserModule,
  ],
  providers: [
    // note: we register Foo even though the token is typed with IBar
    // and the service also expects to receive IBar
    { provide: MyToken, useClass: Foo },
  ],
  bootstrap: [
    MyComponent
  ]
})
export class AppModule { }
import { BrowserModule } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { NgModule } from '@angular/core';

abstract class Bar {
  getBar: () => string;
}

class Foo {
  getFoo: () => string;
}

@Component({
  selector: 'app-main',
  template: '<h1>Hello world</h1>'
})
class MyComponent {
  constructor(bar: Bar) {
    // this will fail since Foo is injected by DI even though the
    // signature says IBar is received
    bar.getBar();
  }
}

@NgModule({
  declarations: [
    MyComponent
  ],
  imports: [
    BrowserModule,
  ],
  providers: [
    // note: we register Foo even though the token is typed with IBar
    // and the service also expects to receive IBar
    { provide: Bar, useClass: Foo },
  ],
  bootstrap: [
    MyComponent
  ]
})
export class AppModule { }
从'@angular/platform browser'导入{BrowserModule};
从'@angular/core'导入{Component};
从“@angular/core”导入{NgModule};
抽象类栏{
getBar:()=>字符串;
}
福班{
getFoo:()=>字符串;
}
@组成部分({
选择器:'应用程序主',
模板:“你好,世界”
})
类MyComponent{
构造函数(bar:bar){
//这将失败,因为即使
//签名表明已收到IBar
getBar();
}
}
@NGD模块({
声明:[
真菌成分
],
进口:[
浏览器模块,
],
供应商:[
//注意:即使令牌是用IBar键入的,我们也会注册Foo
//该服务还希望接收IBar
{provide:Bar,useClass:Foo},
],
引导:[
真菌成分
]
})
导出类AppModule{}