如何正确使用 TypeScript 和 Array.prototype.reduce?

Posted

技术标签:

【中文标题】如何正确使用 TypeScript 和 Array.prototype.reduce?【英文标题】:How to use TypeScript with Array.prototype.reduce correct? 【发布时间】:2022-01-10 23:26:10 【问题描述】:

我有以下reduce 函数,我尝试的任何方法都没有消除错误:

interface ITask 
  id: string;
  was: string;

//sampleData:
const tasks = [
   id: "a", was: "Foo", 
   id: "b", was: "Foo", 
   id: "c", was: "Bad"
]; 
const uniqueList = tasks.reduce<>((acc, current) => 
  const x = acc.find((item: ITask) => item.was === current.was);
  return !x ? acc.concat(current) : acc;
, []);

这给了我:

Property 'find' does not exist on type 'never'.
Property 'was' does not exist on type 'never'.
Property 'concat' does not exist on type 'never'.

current 的值是 ITask 类型,accumulator 的类型是 ITask[]|[],这对我来说是绝对合乎逻辑的。因此,我尝试了:

const uniqueList = tasks.reduce<>((acc: ITask[] | [], current: ITask) => 
  const x = acc.find((item: ITask) => item.was === current.was);
  return !x ? acc.concat(current) : acc;
, []);

这给出了:

Argument of type '(acc: ITask[] | [], current: ITask) => ITask[]' is not assignable to parameter of type '(previousValue: never, currentValue: never, currentIndex: number, array: never[]) => never'.
  Type 'ITask[]' is not assignable to type 'never'.
Argument of type 'ITask' is not assignable to parameter of type 'ConcatArray<never>'.
  Type 'ITask' is missing the following properties from type 'ConcatArray<never>': length, join, slice

编辑:


来自我尝试过的评论:

const uniqueList = tasks.reduce((acc, current: ITask) => 
  const x = acc.find((item: ITask) => item.was === current.was);
  return !x ? acc.concat(current) : acc;
, [] as ITask[] | []);

这给了我:

Property 'find' does not exist on type 'never'.
Property 'concat' does not exist on type 'never'.

【问题讨论】:

相信答案就在这里:***.com/questions/54117100/… 你只需要输入累加器..., [] as ITask[]);tasks.reduce&lt;ITask[]&gt;(...playground 这能回答你的问题吗? give type to accumulator with array reduce typescript 为什么是有条件的?它应该只是useState&lt;ITask[]&gt;,除非您打算在其中存储其他东西? 任何空数组仍然有一个类型。该类型表示只有该类型的元素才能添加到数组中,而不管它是否包含元素。这是一个 codesandox 显示 React 中的类型。 【参考方案1】:

使用更多类型指示器。看到这个stackblitz snippet。

const tasks: ITask[] = [
//    ^ note: typo in question
   id: "a", was: "Foo",
   id: "b", was: "Foo",
   id: "c", was: "Bad",
]; 
const uniqueList: ITask[] = tasks.reduce<ITask[]>((acc: ITask[], current: ITask) => 
  const x = acc.find((item: ITask) => item.was === current.was);
  return !x ? acc.concat(current) : acc;
, []);

【讨论】:

这给了我Expected 0 type arguments, but got 1 for &lt;ITask[]&gt; 我想将: ITask[] 添加到uniqueList。查看编辑后的答案 当我删除 | [] 时,即使没有 &lt;ITask[]&gt;,它也可以正常工作【参考方案2】:

这里是一个在 React 组件中使用 useState 的示例,仅供参考。

TS Playground

export interface ITask 
  id: string;
  was: string;


const tasks: ITask[] = [
  id: "a", was: "Foo", 
  id: "b", was: "Foo", 
  id: "c", was: "Bad"
]; 

// 'tasks' is typed by useState
//const [tasks, setTasks] = useState<ITask[]>([]);

const uniqueList = tasks.reduce<ITask[]>((acc, current) => 
  const x = acc.find((item: ITask) => item.was === current.was);
  return !x ? acc.concat(current) : acc;
, []);

查看完整的codesandbox。

import  useEffect, useState  from "react";

export interface ITask 
  id: string;
  was: string;


interface IProps 
  [tasks: string]: ITask[];


export default function App( tasks: _tasks : IProps) 
  const [tasks, setTasks] = useState<ITask[]>([]);

  useEffect(() => 
    setTasks(_tasks);
  , [_tasks]);

  function uneek() 
    const uniqueList = tasks.reduce<ITask[]>((acc, current) => 
      const x = acc.find((item: ITask) => item.was === current.was);
      return !x ? acc.concat(current) : acc;
    , []);
    setTasks(uniqueList);
  

  return (
    <div className="App">
      <h1>Tasks</h1>
      tasks.length
        ? tasks.map(( id, was ) => (
            <div key=id>
              <h4>was</h4>
            </div>
          ))
        : null
      <button type="button" onClick=uneek>
        uneek
      </button>
    </div>
  );

【讨论】:

以上是关于如何正确使用 TypeScript 和 Array.prototype.reduce?的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript const 断言:如何使用 Array.prototype.includes?

如何在 React 中正确使用 useState 钩子和 typescript?

如何在 TypeScript 中正确导出和导入模块

如何在 TypeScript 中正确要求和声明节点库类型?

如何使用 ts-node-dev 和正确的行号在 Visual Studio Code 中调试 Typescript 代码

如何使用 TypeScript 正确键入 Sequelize JOIN?