处理具有类型联合的列表的 JavaScript reduce 的正确方法是什么?

huangapple go评论59阅读模式
英文:

Proper way to handle types for JS reduce with a list having union of types?

问题

以下是您要翻译的内容:

"Let's say we have a function segregateIds that separates a list of Ids into two parts by checking in a string-to-boolean map.

const segregateIds = (
  ids: string[] | number[],
  optionsById: Record<string, boolean>,
): { correctIds: string[] | number[]; incorrectIds: string[] | number[] } => {

  return ids.reduce<{ correctIds: string[] | number[]; incorrectIds: string[] | number[] }>(
    (accum: { correctIds: string[] | number[]; incorrectIds: string[] | number[] }, id: string | number) => {
      if (optionsById[id]) {
        accum.correctIds.push(id);
      } else {
        accum.incorrectIds.push(id);
      }

      return accum;
    },
    {
      correctIds: [],
      incorrectIds: [],
    }
  );
};

The problem here is that reduce is not accepting a list that has both string[] or number[]. Type coercion is a way to handle this. Is there something better?

Here is the Link to TS Playground

Expecting to resolve the TS error. Tried to type-coerce the accumulator, id but in vain. Tried using lodash reduce, partition but still error remains.

I can use Array<string|number> and pass to lodash partition but that will be tweaking the actual type as Array<string|number> is different from string[] | number[]."

英文:

Let's say we have a function segregateIds that separates a list of Ids into two parts by checking in a string-to-boolean map.


const segregateIds = (
  ids: string[] | number[],
  optionsById: Record&lt;string, boolean&gt;,
): { correctIds: string[] | number[]; incorrectIds: string[] | number[] } =&gt; {

  return ids.reduce&lt;{ correctIds: string[] | number[]; incorrectIds: string[] | number[] }&gt;(
    (accum: { correctIds: string[] | number[]; incorrectIds: string[] | number[] }, id: string | number) =&gt; {
      if (optionsById[id]) {
        accum.correctIds.push(id);
      } else {
        accum.incorrectIds.push(id);
      }

      return accum;
    },
    {
      correctIds: [],
      incorrectIds: [],
    }
  );
};

The problem here is that reduce is not accepting a list that has both string[] or number[]. Type coercion is a way to handle this. Is there something better?

Here is the Link to TS Playground

Expecting to resolve the TS error. Tried to type-coerce the accumulator, id but in vain. Tried using lodash reduce, partition but still error remains.

I can use Array&lt;string|number&gt; and pass to lodash partition but that will be tweaking the actual type as Array&lt;string|number&gt; is different from string[] | number[].

答案1

得分: 3

你可以使用通用类型 T 来接受字符串或数字的数组:

const segregateIds = <T extends string | number>(
  ids: T[],
  optionsById: Record<string, boolean>,
): { correctIds: T[]; incorrectIds: T[] } => {

  return ids.reduce<{ correctIds: T[]; incorrectIds: T[] }>(
    (accum: { correctIds: T[]; incorrectIds: T[] }, id: T) => {
      if (optionsById[id.toString()]) {
        accum.correctIds.push(id);
      } else {
        accum.incorrectIds.push(id);
      }

      return accum;
    },
    {
      correctIds: [],
      incorrectIds: [],
    }
  );
};
英文:

You can use generic type T to accept arrays of strings or numbers:

const segregateIds = &lt;T extends string | number&gt;(
  ids: T[],
  optionsById: Record&lt;string, boolean&gt;,
): { correctIds: T[]; incorrectIds: T[] } =&gt; {

  return ids.reduce&lt;{ correctIds: T[]; incorrectIds: T[] }&gt;(
    (accum: { correctIds: T[]; incorrectIds: T[] }, id: T) =&gt; {
      if (optionsById[id.toString()]) {
        accum.correctIds.push(id);
      } else {
        accum.incorrectIds.push(id);
      }

      return accum;
    },
    {
      correctIds: [],
      incorrectIds: [],
    }
  );

答案2

得分: 3

除了 protob 的回答 之外。

由于您将问题标记为 lodash 标签,您可以使用 _.partition() 而不是 reduce:

const segregateIds = <T extends string | number>(
  ids: T[],
  optionsById: Record<string, boolean>,
): { correctIds: T[]; incorrectIds: T[] } => {
  const [correctIds, incorrectIds] = partition(ids, id => optionsById[String(id)]);
  
  return {
    correctIds,
    incorrectIds
  };
}
英文:

In addition to protob's answer.

Since you marked the question with the lodash tag, you can use _.partition() instead of reduce:

const segregateIds = &lt;T extends string | number&gt;(
  ids: T[],
  optionsById: Record&lt;string, boolean&gt;,
): { correctIds: T[]; incorrectIds: T[] } =&gt; {
  const [correctIds, incorrectIds] = partition(ids, id =&gt; optionsById[String(id)]);

  return {
    correctIds,
    incorrectIds
  };
}

huangapple
  • 本文由 发表于 2023年2月23日 21:17:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75545378.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定