簡體   English   中英

Typescript:重載和檢查泛型

[英]Typescript: overloading and checking against generic type

我有這個界面:

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

和一個實現:

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)
            // ...

    }
}

但它說:

'T' 僅指一種類型,但在此處用作值。ts(2693)'

解決這個問題的正確方法是什么?

請記住,當代碼實際運行時,所有輸入信息都將消失。 因此,您不能依靠類型來確定 object 在運行時是什么。

相反,您必須確定一個值是否與您想要的類型具有相同的特征

其次,您的實現 function 的參數應該是覆蓋中每種類型的聯合類型。


假設您的IModelIRemoteData設置如下:

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

在該條件的每個分支中,您將處理該類型。

請注意,您永遠不會將其與類型進行比較,但您會查看它是否具有您想要的類型的功能。 您可以使用Array.isArray()來查看它是否是一個數組,並且在條件 typescript 中使用時知道這意味着它是一個數組,並且該類型不能再是聯合中的任何非數組類型。

您可以'propName' in item來測試它是否定義了一個可能只存在於您想要的類型之一的屬性。

然后您可以使用else子句來匹配您尚未過濾掉的任何類型。

操場


現在注意額外的覆蓋:

async save(items: IRemoteData<T> | T): Promise<void>; // Added this override

這是條件的數組處理分支所需要的。 問題是,在你知道它是數組之后,你不知道它是什么數組。 所以在迭代項目時,每個項目的類型是:

T | IRemoteData<T>

所以你需要一個重載來處理那個特定的情況。

async save(items: IRemoteData<T> | T): Promise<void>; // Added this override

或者您可以完全消除覆蓋。 當您只有一個可能是類型聯合的參數時,覆蓋就沒有那么有用了,並且更有用的某些參數簽名返回不同的類型。 這是單個 function 定義本身無法做到的事情。

例如:

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

此重載將某些參數類型與某些返回類型聯系起來。 但是您的 function 不需要,並且可以表示為單個 function ,其中它的論點只是許多事物的結合。

所有這意味着這應該工作:

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

操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM