仅当接收函数也是 return 承诺时,如何输入 return 类型成为承诺?
How to type return type to be a promise only if receiving function also returns a promise?
我正在制作这个愚蠢的函数,它将为任何函数制作一个 try/catch 并且 return 它作为一个包含数据和错误的元组
export type CatchReturn<T> = [data: T | undefined, error: unknown | undefined];
export const tcatch = <T>(
tryFunc: (() => T) | (() => Promise<T>)
) => {
try {
const res = tryFunc();
if (res instanceof Promise) {
return res
.then<CatchReturn<T>>((r) => [r, undefined])
.catch<CatchReturn<T>>((e) => [undefined, e]);
} else {
return [res, undefined] as CatchReturn<T>;
}
} catch (e) {
return [undefined, e] as CatchReturn<T>;
}
};
函数按预期运行,但我无法正确键入 return 类型。
目前,return 类型为 CatchReturn<T> | Promise<CatchReturn<T>>
,但我希望 return 类型仅在 tryFunc: (() => T)
和 [=17 时为 CatchReturn<T>
=] 仅当 tryFunc: (() => Promise<T>)
.
例如:
目前如何运作
const syncRes = tcatch(() => {}) // return type is CatchReturn<T> | Promise<CatchReturn<T>>
const asyncRes = tcatch(async () => {}) // return type is CatchReturn<T> | Promise<CatchReturn<T>>
我希望它如何工作
const syncRes = tcatch(() => {}) // return type should be CatchReturn<T>
const asyncRes = tcatch(async () => {}) // return type should be Promise<CatchReturn<T>>
我尝试在 return 类型中使用条件类型,但总是出错,我不能 100% 确定这是否可行。
这是函数重载的工作。您只需为 promise 声明一个函数签名,为其他函数声明另一个函数签名。然后你的实现 returns 两者的结合:
// signatures
export function tcatch<T>(tryFunc: () => Promise<T>): Promise<CatchReturn<T>>
export function tcatch<T>(tryFunc: () => T): CatchReturn<T>
// implementation
export function tcatch<T>(
tryFunc: (() => T) | (() => Promise<T>)
): CatchReturn<T> | Promise<CatchReturn<T>> {
//...
}
这似乎符合您的预期:
const syncRes = tcatch(() => {}) // CatchReturn<void>
const asyncRes = tcatch(async () => {}) // Promise<CatchReturn<void>>
不是那么优雅的方式,但是...
export type CatchReturn<T> = [data: T | undefined, error: unknown | undefined];
type MaybeMappedPromise<F extends () => unknown> = ReturnType<F> extends Promise<infer T> ? Promise<CatchReturn<T>> : CatchReturn<ReturnType<F>>
function tcatch<T extends unknown, F extends (() => T) | (() => Promise<T>)>(
tryFunc: F
): MaybeMappedPromise<F> {
try {
const res = tryFunc();
if (res instanceof Promise) {
return res
.then<CatchReturn<T>>((r) => [r, undefined])
.catch<CatchReturn<T>>((e) => [undefined, e]) as MaybeMappedPromise<F>;
} else {
return [res, undefined] as MaybeMappedPromise<F>;
}
} catch (e) {
return [undefined, e] as MaybeMappedPromise<F>;
}
}
const syncRes = tcatch(() => {}) // return type should be CatchReturn<T>
const asyncRes = tcatch(async () => {}) // return type should be Promise<CatchReturn<T>>
我正在制作这个愚蠢的函数,它将为任何函数制作一个 try/catch 并且 return 它作为一个包含数据和错误的元组
export type CatchReturn<T> = [data: T | undefined, error: unknown | undefined];
export const tcatch = <T>(
tryFunc: (() => T) | (() => Promise<T>)
) => {
try {
const res = tryFunc();
if (res instanceof Promise) {
return res
.then<CatchReturn<T>>((r) => [r, undefined])
.catch<CatchReturn<T>>((e) => [undefined, e]);
} else {
return [res, undefined] as CatchReturn<T>;
}
} catch (e) {
return [undefined, e] as CatchReturn<T>;
}
};
函数按预期运行,但我无法正确键入 return 类型。
目前,return 类型为 CatchReturn<T> | Promise<CatchReturn<T>>
,但我希望 return 类型仅在 tryFunc: (() => T)
和 [=17 时为 CatchReturn<T>
=] 仅当 tryFunc: (() => Promise<T>)
.
例如:
目前如何运作
const syncRes = tcatch(() => {}) // return type is CatchReturn<T> | Promise<CatchReturn<T>>
const asyncRes = tcatch(async () => {}) // return type is CatchReturn<T> | Promise<CatchReturn<T>>
我希望它如何工作
const syncRes = tcatch(() => {}) // return type should be CatchReturn<T>
const asyncRes = tcatch(async () => {}) // return type should be Promise<CatchReturn<T>>
我尝试在 return 类型中使用条件类型,但总是出错,我不能 100% 确定这是否可行。
这是函数重载的工作。您只需为 promise 声明一个函数签名,为其他函数声明另一个函数签名。然后你的实现 returns 两者的结合:
// signatures
export function tcatch<T>(tryFunc: () => Promise<T>): Promise<CatchReturn<T>>
export function tcatch<T>(tryFunc: () => T): CatchReturn<T>
// implementation
export function tcatch<T>(
tryFunc: (() => T) | (() => Promise<T>)
): CatchReturn<T> | Promise<CatchReturn<T>> {
//...
}
这似乎符合您的预期:
const syncRes = tcatch(() => {}) // CatchReturn<void>
const asyncRes = tcatch(async () => {}) // Promise<CatchReturn<void>>
不是那么优雅的方式,但是...
export type CatchReturn<T> = [data: T | undefined, error: unknown | undefined];
type MaybeMappedPromise<F extends () => unknown> = ReturnType<F> extends Promise<infer T> ? Promise<CatchReturn<T>> : CatchReturn<ReturnType<F>>
function tcatch<T extends unknown, F extends (() => T) | (() => Promise<T>)>(
tryFunc: F
): MaybeMappedPromise<F> {
try {
const res = tryFunc();
if (res instanceof Promise) {
return res
.then<CatchReturn<T>>((r) => [r, undefined])
.catch<CatchReturn<T>>((e) => [undefined, e]) as MaybeMappedPromise<F>;
} else {
return [res, undefined] as MaybeMappedPromise<F>;
}
} catch (e) {
return [undefined, e] as MaybeMappedPromise<F>;
}
}
const syncRes = tcatch(() => {}) // return type should be CatchReturn<T>
const asyncRes = tcatch(async () => {}) // return type should be Promise<CatchReturn<T>>