【问题标题】:Typescript, How to write a typed flatten method for arrayTypescript,如何为数组编写类型化的展平方法
【发布时间】:2019-08-03 12:13:51
【问题描述】:

我正在尝试用打字稿写类似的东西 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

但是,我希望能够展平任意深度的嵌套列表;而且我想将所有非数组元素限制为单一类型。

类似:

interface NestedList<T> extends Array<T | NestedList<T>> {}

到目前为止我已经得到了这个:

export const flat = <T>(ls: NestedList<T>): T[] => {
   const reducer = (acc: T[], it: T | NestedList<T>): T[] => acc.concat(
      Array.isArray(it) ? it.reduce(reducer, []) : it
   );

   return ls.reduce(reducer, []);
};

但是,类型推断似乎不起作用

   it('works with type inference', () => {
      interface Foo<T> { v: T; }

      const data: { [_: string]: { [_: string]: Foo<number> } } = {
         bar: { x: { v: 1 } },
         moo: { y: { v: 2 }, z: { v: 3 } }
      };

      const nested: Foo<number>[][] = Object.values(data).map(val => Object.values(val));
      const list2: Foo<number>[] = flat(nested);
      expect(list2).toEqual([{ v: 1 }, { v: 2 }, { v: 3 }]);
   });

它在这一行收到类型错误:

const list2: Foo<number>[] = flat(nested);

错误:

Type '(Foo<number>[] | ConcatArray<Foo<number>[]>)[]' is not assignable to type 'Foo<number>[]'.
  Type 'Foo<number>[] | ConcatArray<Foo<number>[]>' is not assignable to type 'Foo<number>'.
    Property 'v' is missing in type 'Foo<number>[]' but required in type 'Foo<number>'

我在这里缺少什么?任何帮助表示赞赏。

【问题讨论】:

  • 看看--lib esnext.array是怎么做到的:source
  • 似乎限制了深度。这是类型系统的基本限制吗?
  • 最终,是的。类型系统可以理论上表达“任意嵌套数组”的概念,但它遇到了递归定义类型的问题,大约有 23 个嵌套(请参阅我的回答 here)。该策略 TypeScript 自己的工程师使用它来定义类型系统中最常见的用例,并依靠用户为更不寻常的情况提供提示/断言。
  • 在试图理解为什么会发生这种情况时,我发现它在更简单的情况下:``` const foo = (bar: (l: NestedList) => T, baz : string[]): string => bar(baz); ``` 这编译但没有&lt;string&gt; 会失败。我仍然不明白为什么,但我认为这可能会让其他人更容易理解。

标签: typescript type-inference type-systems


【解决方案1】:

我偶然发现了和你一样的问题。这是我想出的解决方案:

function flat<U>(arr: U[][]): U[] {
    if ((arr as unknown as U[]).every((val) => !Array.isArray(val))) {
        return (arr as unknown as U[]).slice();
    }
    return arr
        .reduce((acc, val) => acc
            .concat(Array.isArray(val) ? flat((val as unknown as U[][])) : val), []);
}

console.log(flat([[1,2],[[[3]]],4])

希望对你有帮助:)

【讨论】:

    猜你喜欢
    • 2010-09-09
    • 2021-10-10
    • 2019-02-12
    • 2011-06-23
    • 2019-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    相关资源
    最近更新 更多