typescript - 无法使方法重载与歧视性联合一起工作。怎么了?
问题描述
as IUpdateRequestPromiseProxy<TEntity>
在没有断言的情况下如何使以下代码工作?
import { Id } from 'app/core/persistence';
import { IPersistence } from '..';
import { IBaseEntity } from '../../..';
/*
* Missing changeFn indicates delete
*/
type IChangeRequestPromiseProxy<TEntity extends IBaseEntity> =
| IUpdateRequestPromiseProxy<TEntity>
| IDeleteRequestPromiseProxy;
interface IUpdateRequestPromiseProxy<TEntity extends IBaseEntity> {
id: Id;
kind: 'update';
resolve(value: IPersistence<TEntity>): void;
reject(reason: any): void;
changeFn(entity: IPersistence<TEntity>): IPersistence<TEntity>;
}
interface IDeleteRequestPromiseProxy {
id: Id;
kind: 'delete';
resolve(value: void): void;
reject(reason: any): void;
}
export class QueueService<TEntity extends IBaseEntity> {
private changeRequestsQueue: Array<IChangeRequestPromiseProxy<TEntity>> = [];
private flushingQueueMutex: boolean = false;
public async enqueue(id: Id, kind: 'delete'): Promise<void>;
public async enqueue(
id: Id,
kind: 'update',
changeFn: (entity: IPersistence<TEntity>) => IPersistence<TEntity>,
): Promise<IPersistence<TEntity>>;
public async enqueue(
id: Id,
kind: 'delete' | 'update',
changeFn?: (entity: IPersistence<TEntity>) => IPersistence<TEntity>,
): Promise<IPersistence<TEntity> | void> {
let promise: Promise<IPersistence<TEntity> | void>;
switch (kind) {
case 'delete':
promise = new Promise<void>(async (resolve, reject) => {
this.changeRequestsQueue.push({
id,
kind,
resolve,
reject,
});
});
break;
case 'update':
default:
promise = new Promise<IPersistence<TEntity>>(async (resolve, reject) => {
this.changeRequestsQueue.push({
id,
kind,
resolve,
reject,
changeFn,
} as IUpdateRequestPromiseProxy<TEntity>);
});
break;
}
return promise;
}
}
如果我删除断言,我会收到错误:
Argument of type '{ id: string; kind: "update"; resolve: (value?: IPersistence<TEntity> | PromiseLike<IPersistence<TEntity>> | undefined) => void; reject: (reason?: any) => void; changeFn: ((entity: IPersistence<TEntity>) => IPersistence<...>) | undefined; }' is not assignable to parameter of type 'IChangeRequestPromiseProxy<TEntity>'.
Type '{ id: string; kind: "update"; resolve: (value?: IPersistence<TEntity> | PromiseLike<IPersistence<TEntity>> | undefined) => void; reject: (reason?: any) => void; changeFn: ((entity: IPersistence<TEntity>) => IPersistence<...>) | undefined; }' is not assignable to type 'IUpdateRequestPromiseProxy<TEntity>'.
Types of property 'changeFn' are incompatible.
Type '((entity: IPersistence<TEntity>) => IPersistence<TEntity>) | undefined' is not assignable to type '(entity: IPersistence<TEntity>) => IPersistence<TEntity>'.
Type 'undefined' is not assignable to type '(entity: IPersistence<TEntity>) => IPersistence<TEntity>'.ts(2345)
解决方案
问题是打字稿不跟踪重载之间kind
的关系。即使您在分支上,就 ts 而言,changeFn
因此仍然可能是未定义的。changeFn
kind === 'update'
最简单的解决方案是使用非空断言:
this.changeRequestsQueue.push({
id,
kind: 'update',
resolve,
reject,
changeFn: changeFn!,
});
如果您想要完整的非断言版本,可以使用参数中的可区分元组来完成,尽管我不确定是否值得额外的复杂性:
export class QueueService<TEntity extends IBaseEntity> {
private changeRequestsQueue: Array<IChangeRequestPromiseProxy<TEntity>> = [];
private flushingQueueMutex: boolean = false;
public async enqueue(id: Id, kind: 'delete'): Promise<void>;
public async enqueue(
id: Id,
kind: 'update',
changeFn: (entity: IPersistence<TEntity>) => IPersistence<TEntity>,
): Promise<IPersistence<TEntity>>;
public async enqueue(
id: Id,
...r: ['delete'] | ['update', (entity: IPersistence<TEntity>) => IPersistence<TEntity>],
): Promise<IPersistence<TEntity> | void> {
let promise: Promise<IPersistence<TEntity> | void>;
switch (r[0]) {
case 'delete':
promise = new Promise<void>(async (resolve, reject) => {
this.changeRequestsQueue.push({
id,
kind: r[0],
resolve,
reject,
});
});
break;
case 'update':
default:
promise = new Promise<IPersistence<TEntity>>(async (resolve, reject) => {
this.changeRequestsQueue.push({
id,
kind: r[0],
resolve,
reject,
changeFn: r[1],
});
});
break;
}
return promise;
}
}
推荐阅读
- nativescript - NativeScript:卸载 macOS + Android 开发环境
- javascript - How do I fix bind message gives 4 parameters but prepared statement "" requires 5
- json - 谷歌脚本从 cURL 获取 JSON
- sql-server - 使用 Windows 身份验证和模拟用户将 PowerShell 连接到 SQL Server
- applescript - 引用 AppleScript 中的属性
- python - Python Typing:如何处理子类中具有不同元素类型的列表类型提示?
- python - 如何使用 python 直接打开缩放窗口?
- reactjs - JSX 元素类型“导航栏”没有任何构造或调用签名
- reactjs - react-hook-form 会在没有名称道具的情况下工作吗?
- amazon-web-services - awssdk,maven - 要使用哪个 groupId 和 artifactId 名称(aws,core)?