如何在打字稿中仅返回已解决的承诺,而忽略错误?

时间:2020-09-10 06:48:42

标签: javascript typescript promise typescript-generics

我已经创建了该函数,该函数应采用Promises数组,并且仅返回已解决的Promises。错误必须忽略。因此,似乎有点像Promise.all,但没有错误。问题是用打字稿正确编写函数。以前,仅使用JS可以达到预期的效果。

function promiseIgnoreErrors<T> (arrayOfPromise: Array<T>)  {
    const isArrayEmpty =
      Array.isArray(arrayOfPromise) && arrayOfPromise.length === 0;
  
    return new Promise((resolve, reject) => {
      if (isArrayEmpty) reject(new Error('Forever pending array'));
  
      let resolvedArray: Array<T> = []
      
      let resolvedCounter: number = 0;
  
      arrayOfPromise.forEach((promise, index) => {
        if (promise instanceof Promise) {
          promise
            .then((data) => {
              resolvedArray[index] = data
              resolvedCounter++;      
              if (arrayOfPromise.length === resolvedCounter) resolve(resolvedArray)   
            })
            .catch(() => {
              resolvedCounter++;
              if (arrayOfPromise.length === resolvedCounter) resolve(resolvedArray)
            })
        } else {
          resolvedArray[index] = promise
          resolvedCounter++;
          if (arrayOfPromise.length === resolvedCounter) resolve(resolvedArray)   
        }
      })
    });
  };

问题简短介绍。我的变量:

const p1 = new Promise((resolve) => setTimeout(() => resolve('JS'), 500))
const p2 = 22
const p3 = new Promise((reject) => setTimeout(() => reject(new Error('Oops')), 100))
const p4 = new Promise((resolve) => setTimeout(() => resolve('TS'), 200))

当我拥有变量并将其作为数组传递时,

promiseIgnoreErrors([p1, p2, p3, Promise.reject(10), p4])

我希望:

Promise {<pending>}
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(3)
// ['JS', 22, 'TS']

现在我有:

Promise {<pending>}
    [[PromiseState]]: "fulfilled"
    [[PromiseResult]]: Array(5)
    // ['JS', 22, Error: 'Oops, ?, 'TS']

您可以在控制台中显示我的问题: Playground

我认为问题是这里的泛型,也正是这一行:

let resolvedArray: Array<T> = []

因为它指示返回的表必须包含与输入中相同的元素。也许应该类似于:

let resolvedArray: Array<K> extends T = []

我当然知道上面的行是错误的,但是也许我应该遵循这个想法。或者也许我的功能不正常?

请提供任何帮助!

2 个答案:

答案 0 :(得分:0)

这似乎足够。

这个想法是ERRORED是一个哨兵对象;如果数组中的一个承诺抛出了,我们将其捕获并将其转换为ERRORED

isNotErrored(x)是一种类型保护功能,可确保TypeScript x不是哨兵,因此results.filter(isNotErrored)的类型最终是T[],而不是{{1 }}。

(T | '__ERRORED__')[]

例如

const ERRORED = '__ERRORED__';
type ErroredType = typeof ERRORED;

function isNotErrored<T>(x: T | ErroredType): x is T {
  return x !== ERRORED;
}

async function promiseIgnoreErrors<T>(promises: Array<Promise<T>>): Promise<Array<T>> {
  const results = await Promise.all(promises.map(p => p.catch(() => ERRORED as ErroredType)));
  return results.filter(isNotErrored);
}

日志


promiseIgnoreErrors([Promise.resolve(8), Promise.reject("oh no"), Promise.resolve(16)]).then(r => {
  console.log(r);
});

忽略拒绝。

编辑:

对于原始输入

[8, 16]

这不会进行类型检查,因为并非所有输入都是Promise,这是恕我直言的正确行为。正如评论中所讨论的,裸值应使用const p1 = new Promise((resolve) => setTimeout(() => resolve('JS'), 500)) const p2 = 22 const p3 = new Promise((reject) => setTimeout(() => reject(new Error('Oops')), 100)) const p4 = new Promise((resolve) => setTimeout(() => resolve('TS'), 200)) 包装,即

Promise.resolve()

或者您可以在内部执行此操作:

const p2 = Promise.resolve(22)

答案 1 :(得分:0)

async function promiseIgnoreErrors<T>(arrayOfPromise: Array<T>) {
  const promises = await Promise.all(arrayOfPromise.map((p) => promisify(p)))
  return promises.filter((v) => v != null)
}

const promisify = <T>(value: T) =>
  Promise.resolve(value)
    .then((v) => (v instanceof Error ? null : v))
    .catch(() => null)


const r = promiseIgnoreErrors([p1, p2, p3, p4, p5])

console.log(r)                // Promise { <pending> }
r.then((x) => console.log(x)) // [ 'JS', 22, 'TS' ]

更新

已删除flatMap版本,以免造成混淆

相关问题