在 TypeScript 中展平数组数组

问题描述 投票:0回答:10

我想将

string[][]
压扁为
string[]

数十个SO答案中给出的建议是:

[].concat(...arrays)

但这给了我这个错误:

“string[]”类型的参数不可分配给“ConcatArray”类型的参数。
属性“切片”的类型不兼容。
类型 '(start?: number | undefined, end?: number | undefined) => string[]' 不可分配给类型 '(start?: number | undefined, end?: number | undefined) => never[]' .
类型“string[]”不可分配给类型“never[]”。
类型“string”不可分配给类型“never”。

我尝试的另一种方法是:

let foo: string[][] = [["a", "b", "c"], ["a", "b", "c"], ["a", "b", "c"]];
let bar = [].concat(...foo);

这给出了类似的错误:

“string[]”类型的参数不可分配给“ConcatArray”类型的参数。

为什么它对除了我以外的所有人都有效?

typescript
10个回答
85
投票

试试这个:

const a = [["a", "b", "c"], ["a", "b", "c"], ["a", "b", "c"]]
const result = a.reduce((accumulator, value) => accumulator.concat(value), []);
console.log(result)


52
投票

您可以使用

flat()

展平数组
let foo: string[][] = [["a", "b", "c"], ["a", "b", "c"], ["a", "b", "c"]];
let bar = foo.flat()

日志

console.log(bar)   // a,b,c,a,b,c,a,b,c 

更新

通过将类型更正为 string[],您还可以使用

concat

let foo: string[][] = [["a", "b", "c"], ["a", "b", "c"], ["a", "b", "c"]];
let bar : string[] = []
bar = bar.concat(foo[0], foo[1], foo[2])

20
投票

这是最简单的选择:

let bar = ([] as string[]).concat(...foo);

类似于@Kokodoko 的方法,但输入是内联的。


18
投票

这是一个通用解决方案:

function flatten<T>(arr: T[][]): T[] {
  return ([] as T[]).concat(...arr);
}

以及深度/递归扩展:

type NestedArray<T> = Array<NestedArray<T> | T>;

function flattenDeep<T>(input: NestedArray<T>): T[] {
  return flatten(input.map(x => Array.isArray(x) ? flattenDeep(x) : [x]));
};

这个答案对于深度扁平化可能更有效,我只是很高兴尝试写一些对我来说更优雅的东西。


10
投票

.flat() 也会给出类型错误。 您可以使用泛型来解决这个问题

let st : string[][] | Array<string> = [['a'] , ['b']]
    let bar = [].concat(...st);
    console.log(bar)

无论哪种方式,你的决定。只需知道您的类型声明不正确即可。


6
投票

代码

const res = [].concat(...foo);

应该可以。我猜这是 tsconfig 中的错误配置导致了您的错误。确保 tsconfig 的

es2015
数组中至少有
es2018
(更好的
lib
)。要使新的
flat
正常工作,如 kokodoko 所示,请确保还添加
esnext

"lib": [
  "es2018",
  "dom",
  "esnext"
]

5
投票

我相信你有 strictNullCheck: true

没有上下文类型的空数组([].concat(arg) 中的 [])在 strictNullChecks 下被推断为 never[]。并且 never 不能从任何其他类型分配。

([] as any[]).concat(foo);应该可以解决问题


5
投票

对于更深层嵌套的数组,例如:

[1, 2, 3, [4, [5, [6, [7]]]]]

type NestedArray<T> = Array<NestedArray<T> | T>;

const flatten = <T>(input: NestedArray<T>, acc: T[] = []): T[] => {
  return input.reduce((_: T[], current) => {
    if (Array.isArray(current)) return flatten(current, acc);  
    acc.push(current);
    return acc;
  }, []);
};

用途:

console.log(flatten([1, 2, 3, [4, [5, [6, [7]]]]]));

0
投票

来自Steven的答案适用于我的玩笑测试,但由于我无法弄清楚的约束错误,不适用于我实际的 Angular 15 应用程序。稍微修改为常规递归函数以保持 Typescript 安静:

import { Injectable} from '@angular/core';

export type NestedArray<T> = Array<NestedArray<T> | T>;

export class ArrayHelper {
 
  public static flatten = <T>(input: NestedArray<T>, res: T[] = []): T[] => {
    input.forEach((el: T | NestedArray<T>) => {
      if (Array.isArray(el)) {
        ArrayHelper.flatten(el, res);
      } else {
        res.push(el);
      }
    });

    return res;
  };
}

测试示例:


 describe('flattening', () => {
      it('pass through', () => {
        expect(ArrayHelper.flatten(['hi', 'there'])).toHaveLength(2);
      });

      it('2 level', () => {
        expect(ArrayHelper.flatten(['hi', 'there', ['that', 'is', 'all', 'folks']])).toHaveLength(6);
      });

      it('as per SO', () => {
        expect(ArrayHelper.flatten([1, 2, 3, [4, [5, [6, [7]]]]])).toHaveLength(7);
      });

      
    });

0
投票

var foo = [["a", "b", "c"], ["a", "b", "c"], ["a", "b", "c"],[['x','y','z']]];
var bar = foo.flat(Infinity)

console.log(bar)

信息:带有参数 Infinity 的 Array.Flat 意味着将其展平,直到不存在嵌套数组。

© www.soinside.com 2019 - 2024. All rights reserved.