获取通用Angular服务中的类型名称

时间:2018-12-15 23:55:36

标签: angular typescript

我可以这样获得对象的名称:

let name = obj.prototype.constructor.name;

但是我想做的是获取通用Angular服务中通用类型的名称。

@Injectable({
  providedIn: 'root'
})
export class MyService<T> {

    private _value: T;

    constructor(){}

    //... other methods

    private error(error: any)
    {
      console.log(`Error for service type: ${_value.prototype.constructor.name}`)
    }

}

_value.prototype.constructor.name不起作用,类型T不存在原型。

我见过专门针对打字稿的帖子,指出只有在构造函数采用类型参数的情况下才有可能,因为一旦转译的类型声明被删除,因为它们在javascript中不存在,便成为可能。

随着angular通过依赖注入创建此服务时,传递该类型的正确方法是什么,以便可以以允许我将名称读取为字符串的方式进行实例化?

我在这篇文章中看到了:How to get name of generic type T inside service in Angular

它说要使用此功能:

function createInstance<T>(type: new() => T): T {
    return new type();
}

但是我看不到我应该如何在上面的角度服务中使用此功能。

如何在服务中获取字符串?

1 个答案:

答案 0 :(得分:2)

您不能通过类型检查的方式来执行此操作。
如果您可以使用typeof T

// doesn't work
@Injectable({
  providedIn: 'root'
})
export class MyService<T> {
  private _value: T;
  private _type: typeof T = T;
                        ^^^^^ 'T' refers to a type but is being used as a value
  private error() {
    console.log(`Error for service type: ${this._type.prototype.constructor.name}`)
  }
}

您可以进行一些调整以使此工作有效。在继续之前,请意识到您将丢失一些类型检查。

  • typeof T替换为Function(对于类,基本上是any
  • 添加一个构造函数参数,用于传递实际类型
  • 删除@Injectable()装饰器... Angular不会帮助您找到实际的类型。

重构后:

export class MyService<T> {
  private _value: T;
  private _type: Function;
  constructor(type: Function) {
    this._type = type;
  }
  private error() {
    console.log(`Error for service type: ${this._type.prototype.constructor.name}`)
  }
}

基本用法如下:

let myStringService = new MyService<String>(String);

只是为了证明您丢失了类型检查,这将编译没有错误:

class HeckinBamboozled { }
let myNumberService = new MyService<Number>(HeckinBamboozled);

现在,您有两个选择可以使用DI进行此操作。最简单的方法是创建和提供派生类型。

@Injectable({ providedIn: 'root' })
export class MyStringService extends MyService<String> {
  constructor() {
    super(String);
  }
}

其他服务很容易消耗掉它。

@Injectable()
export class OtherService {
  constructor(private stringService: MyStringService) {
  }
}

第二种方法更新颖,并且使用注入令牌。

export const STRING_SERVICE = new InjectionToken<MyService<String>>('My String Service', {
  providedIn: 'root',
  factory: () => new MyService<String>(String)
});

但是它更难食用。

@Injectable()
export class OtherService {
  constructor(@Inject(STRING_SERVICE) private stringService: MyService<String>) {
  }
}

实际上,它比第一个选项的类型安全性差。这样编译不会出错。

@Injectable()
export class OtherService {
  constructor(@Inject(STRING_SERVICE) private stringService: MyService<HeckinBamboozled>) {
  }
}