【发布时间】: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); ``` 这编译但没有 <string>会失败。我仍然不明白为什么,但我认为这可能会让其他人更容易理解。
标签: typescript type-inference type-systems