TypeScript Promise 泛型类型

78

我有一个像下面这样的示例Promise函数。成功时返回number,失败时返回string。编译器要求指定某种通用类型到promise中。在这种情况下,我需要指定什么类型?我应该像Promise<number>Promise<number | string>那样指定吗?

function test(arg: string): Promise {
    return new Promise((resolve, reject) => {
        if (arg === "a") {
            resolve(1);
        } else {
            reject("1");
        }
    });
}

2
你尝试过 Promise<number|string> 吗? - jonrsharpe
1
它这样做不会抱怨。这样做是正确的吗?指定解析和拒绝类型都可以吗? - VJAI
4个回答

155

Promise的通用类型应与函数的非错误返回类型相对应。错误隐式地是any类型,并且没有在Promise通用类型中指定。

所以例如:

function test(arg: string): Promise<number> {
    return new Promise<number>((resolve, reject) => {
        if (arg === "a") {
            resolve(1);
        } else {
            reject("1");
        }
    });
}

5
有没有一种方式可以指定错误情况的类型?例如,我有一个承诺(promise),如果被拒绝了,就会用一个自定义对象来拒绝。我能否使用 Promise<T> 内置的泛型类型来指定拒绝值的类型?谢谢! - tonix
2
@tonix 您使用自定义对象拒绝 Promise 的确切原因是因为 Promise 具有 any 错误类型。错误类型无法约束,因为 Promise 中的任何运行代码都可能抛出任何内容,而不仅仅是普通的 Error。 (请参见 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw 。它是 throw expression)。由于 Promise 是一个泛型对象,无法控制其中运行的内容,而且期望您(开发人员)控制其中运行的内容也很繁琐/过分,因此无法约束错误类型。 - George Pantazes
3
@GeorgePantazes:我并不认为如果可以可选地指定拒绝类型会很繁琐。此外,人们也无法控制解析值内部的运行情况,但仍然可以指定它。 - Brett Zamir

5
您可以定义一个自定义的Promise类型,它实际上也关心拒绝的类型。您也可以只给它一个类型,而拒绝类型将是any,就像普通Promise一样。

type CustomPromise<T, F = any> = {
    catch<TResult = never>(
        onrejected?: ((reason: F) => TResult | PromiseLike<TResult>) | undefined | null
    ): Promise<T | TResult>;
} & Promise<T>;

function test(arg: string): CustomPromise<number, string> {
    return new Promise((resolve, reject) => {
        if (arg === "a") {
            resolve(1);
        } else {
            reject("1");
        }
    });
}

const myPromise = test("a");
myPromise.then((value) => {}); //value is of type `number`
myPromise.catch((reason) => {}); //reason is of type `string`

1
太好了。我现在将使用这个“FullyTypedPromise”。 - Pascal Ganaye

0

另一种解决方案

P.S.(顺便说一下)

通用类型“Promise”需要1个类型参数。ts(2314)

function test(arg: string){
    return new Promise<number>((resolve, reject) => {
        if (arg === "a") {
            resolve(1);
            // (parameter) resolve: (value: number | PromiseLike<number>) => void
        } else {
            // (parameter) reject: (reason?: any) => void
            reject("1");
        }
    });
}

enter image description here


-1
function test(arg: string) {
   return new Promise((resolve: (value: number) => void, reject) => {
    if (arg === "a") {
        resolve(1);
    } else {
        reject("1");
    }
  });
}

20
仅含代码的答案通常可以通过添加一些解释来改善其可读性并说明它们的工作原理和原因。当向一个已有被接受的答案的老问题中添加答案时,这一点尤为重要。请指出你的答案解决了问题的哪个新方面,并注意时间的流逝和新版本的引入是否会影响答案。 - Jason Aller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接