[英]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.