Typescript:重载并检查泛型类型

Typescript:重载并检查泛型类型,typescript,Typescript,我有这个界面: export interface ICRUDService<T extends IModel> { save(item: T): Promise<void>; save(items: T[]): Promise<void>; save(item: IRemoteData<T>): Promise<void>; save(items: IRemoteData<T>[]): Pr

我有这个界面:

export interface ICRUDService<T extends IModel> {

    save(item: T): Promise<void>;
    save(items: T[]): Promise<void>;
    save(item: IRemoteData<T>): Promise<void>;
    save(items: IRemoteData<T>[]): Promise<void>;
    save(item: Partial<T>): Promise<void>;
}
导出接口ICRUDService{
保存(项目:T):承诺;
保存(项目:T[]):承诺;
保存(项目:IRemoteData):承诺;
保存(项目:IRemoteData[]):承诺;
保存(项目:部分):承诺;
}
以及一项实施:

export abstract class AbstractCRUDServiceImpl<T extends IModel> implements ICRUDService<T> {

    async save(item: T): Promise<void>;
    async save(items: T[]): Promise<void>;
    async save(item: IRemoteData<T>): Promise<void>;
    async save(items: IRemoteData<T>[]): Promise<void>;
    async save(item: Partial<T>): Promise<void>;

    async save(item: any): Promise<void> {

        if (typeof item === T)
            // ...

    }
}
导出抽象类AbstractCRUDServiceImpl实现ICRUDService{
异步保存(项目:T):承诺;
异步保存(项:T[]):承诺;
异步保存(项目:IRemoteData):承诺;
异步保存(项:IRemoteData[]):承诺;
异步保存(项目:部分):承诺;
异步保存(项目:任意):承诺{
如果(项目类型===T)
// ...
}
}
但它说:

“T”仅指类型,但用作值 这里是ts(2693)'


解决这个问题的正确方法是什么?

请记住,当代码实际运行时,所有键入信息都将消失。因此,您不能依赖类型来确定运行时对象是什么

相反,您必须确定值是否具有与所需类型相同的功能

其次,实现函数的参数应该是一个类型,它是覆盖中每种类型的并集


假设您的
IModel
IRemoteData
设置如下:

interface IRemoteData<T> {
  remoteData: T
}
interface IModel {
  id: number
}
export abstract class AbstractCRUDServiceImpl<T extends IModel> implements ICRUDService<T> {
  async save(item: T): Promise<void>;
  async save(items: T[]): Promise<void>;
  async save(item: IRemoteData<T>): Promise<void>;
  async save(items: IRemoteData<T>[]): Promise<void>;
  async save(item: Partial<T>): Promise<void>;
  async save(items: IRemoteData<T> | T): Promise<void>; // Added this override

  async save(item: T | T[] | IRemoteData<T> | IRemoteData<T>[] | Partial<T>): Promise<void> {
    if (Array.isArray(item)) {
      // item is array in this scope, iterate over each item and save them
      for (const singleItem of item) {
        await this.save(singleItem)
      }
    } else {
      // item is not an array in this scope
      if ('id' in item) {
        item // T | Partial<T>
      } else {
        item // IRemoteData<T>
      }
    }
  }
}
这是条件的数组处理分支所必需的。问题是,当你知道它是数组之后,你就不知道它是什么数组了。因此,在迭代项目时,每个项目的类型为:

T | IRemoteData<T>
此重载将某些参数类型绑定到某些返回类型。但是你的函数不需要这样,可以用一个函数来表示,它的参数是很多东西的简单结合

所有这一切都意味着这应该是可行的:

export abstract class AbstractCRUDServiceImpl<T extends IModel> {
  async save(item: T | T[] | IRemoteData<T> | IRemoteData<T>[] | Partial<T>): Promise<void> {
    if (Array.isArray(item)) {
      // item is array in this scope, iterate over each item and save them
      for (const singleItem of item) {
        await this.save(singleItem)
      }
    } else {
      // item is not an array in this scope
      if ('id' in item) {
        item // T | Partial<T>
      } else {
        item // IRemoteData<T>
      }
    }
  }
}
导出抽象类AbstractCRUDServiceImpl{
异步保存(项目:T | T[]| IRemoteData | IRemoteData[]|部分):承诺{
if(阵列isArray(项目)){
//项是此范围中的数组,遍历每个项并保存它们
用于(项目的常量单个项目){
等待此操作。保存(singleItem)
}
}否则{
//项不是此作用域中的数组
如果(项目中的“id”){
项目//T |部分
}否则{
项目//IRemoteData
}
}
}
}

什么是
IModel
IRemoteData
?另外,您确定要在此处进行覆盖吗?由于返回类型没有改变,您只需要将一个方法定义为
save(item:t | t[]| IRemoteData | IRemoteData[]| Partial):Promise
IModel是一个基本类型,它只有一个“id”字段。IRemoteData是带有一些额外字段的T的包装器。当然,我只能定义一个方法,但这不是方法重写的重点吗?同时为intellisense提供选项。@AlexWayne,即使我将它们合并到一个方法中,我仍然会遇到同样的问题。。?
async save(items: IRemoteData<T> | T): Promise<void>; // Added this override
function foo(a: number): string
function foo(a: string): number
function foo(a: number|string): number|string {
  if (typeof a === 'string') {
    return 123
  } else {
    return 'a string'
  }
}
export abstract class AbstractCRUDServiceImpl<T extends IModel> {
  async save(item: T | T[] | IRemoteData<T> | IRemoteData<T>[] | Partial<T>): Promise<void> {
    if (Array.isArray(item)) {
      // item is array in this scope, iterate over each item and save them
      for (const singleItem of item) {
        await this.save(singleItem)
      }
    } else {
      // item is not an array in this scope
      if ('id' in item) {
        item // T | Partial<T>
      } else {
        item // IRemoteData<T>
      }
    }
  }
}