【问题标题】:How to infer parameter type of a overloaded callback?如何推断重载回调的参数类型?
【发布时间】:2022-12-18 11:53:05
【问题描述】:
我正在尝试在打字稿中定义一个类型安全的 nodejs 风格的回调。我想将 err 定义为 Error(如果存在)或将 data 定义为 T(如果不存在)。
- 如果我使用这段代码
export interface SafeCallback<T> {
(err: unknown): void;
(err: undefined, data: T): void;
}
const subscribe = <T>(callback: SafeCallback<T>) => {
let result: T;
try {
// result = something
} catch (e) {
callback(e);
return;
}
callback(undefined, result);
};
subscribe<{id: string}>((err, data?) => {
if (!err) {
console.log(data.id);
}
});
我得到'data' is of type 'unknown'.
- 如果我从
data 中删除问号,我得到
Argument of type '(err: undefined, data: { id: string; }) => void' is not assignable to parameter of type 'SafeCallback<{ id: string; }>'
我尝试了在第一次重载中定义 err: Error 的两种情况,但它没有改变任何东西。
还有什么我应该尝试的吗?
谢谢!
【问题讨论】:
-
This approach 是我能得到的最接近的并且是类型安全的。我尝试过的任何其他方法都遇到了限制或错误。它能满足您的需求吗?如果是这样,我可以写一个答案来解释;如果没有,我错过了什么?
-
标签:
typescript
callback
type-safety
【解决方案1】:
有条件的类型可能是?
export type SafeCallback<T> = {
<errorType>(err: errorType, data: errorType extends undefined ? T : null): void;
};
const subscribe = <T>(callback: SafeCallback<T>) => {
let result: T;
try {
// result logic
} catch (e) {
callback(e, null);
return;
}
callback(undefined, result);
};
subscribe<{ id: string }>((err, data) => {
if (data !== null) {
console.log("data = " + data.id);
} else {
console.log("err = " + err);
}
});
编辑 :
刚看到@jclaz 回复。从他的回应中摘取一些东西:
export interface SafeCallback3<T> {
<errorType>(...args:( errorType extends undefined ? [err: undefined, data: T] : [err: errorType] )): void;
}
这可以防止在 catch 中抛出错误。
const subscribe3 = <T>(callback: SafeCallback3<T>) => {
let result: T;
try {
// ...
} catch (e) {
callback(e);
return;
}
callback(undefined, result);
};
subscribe<{ id: string }>((...args) => {
const [err, data] = args;
if (!err) {
console.log(data.id);
} else {
err.message
}
});