[英]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 的參數應該是覆蓋中每種類型的聯合類型。
假設您的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>
}
}
}
}
在該條件的每個分支中,您將處理該類型。
請注意,您永遠不會將其與類型進行比較,但您會查看它是否具有您想要的類型的功能。 您可以使用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.