我正在尝试创建一个可以平整打字稿中嵌套数组的函数。
到目前为止,我有这个:
function flattenArrayByKey<T, TProp extends keyof T>(array: T[], prop: TProp): T[TProp] {
return array.reduce((arr: T[TProp], item: T) => [...arr, ...(item[prop] || [])], []);
}
其中的array.reduce
确实可以实现我想要的功能,但是我无法让泛型与我想要的功能完美配合。我认为我的问题是item[prop]
返回any
,因为它无法推断item[prop]
返回T[TProp]
。
我想要的是一个可以采用这种结构的函数:
interface MyInterface {
arrayProperty: string[];
anotherArray: number[]
someNumber: number;
}
const objectsWithNestedProperties: MyInterface[] = [
{
arrayProperty: ['hello', 'world'],
anotherArray: [1, 2],
someNumber: 1,
},
{
arrayProperty: ['nice', 'to'],
anotherArray: [3, 4],
someNumber: 2,
},
{
arrayProperty: ['meet', 'you'],
anotherArray: [5, 6],
someNumber: 3,
},
];
并返回一个包含所有嵌套数组内容的数组。
const result = flattenArrayByKey(objectsWithNestedProperties, 'arrayProperty');
result
应该看起来像['hello', 'world', 'nice', 'to', 'meet', 'you']
基本上,我是从C#的linq中寻找SelectMany
。
答案 0 :(得分:1)
注意:以下答案已在TS3.5上以--strict
模式进行了测试。如果使用其他版本或编译器标志,则里程可能会有所不同。
如何?
function flattenArrayByKey<K extends keyof any, V>(array: Record<K, V[]>[], prop: K): V[] {
return array.reduce((arr, item) => [...arr, ...(item[prop] || [])], [] as V[]);
}
您必须告诉编译器T[TProp]
将是一个数组。而不是尝试走那条路线,我将泛型设为K
(您在叫TProp
)和V
,这是array[number][K]
数组属性的元素类型。然后,您可以将array
键入为Record<K, V[]>[]
而不是T[]
(Record<K, V[]>
是一个对象,其键K
的属性为V[]
类型) 。它返回一个V[]
。
现在,尽管您确实需要告诉它,作为reduce
的第二个参数的初始空数组应该是V[]
(因此{ {1}}。
这应该可以按您想要的方式工作。希望能有所帮助;祝你好运!
更新:当对象具有不同类型的数组时,上述内容似乎无法很好地推断出来。您可能会发现自己必须像[] as V[]
那样显式地键入它,这很多余而且很烦人。
以下是更复杂的签名,但具有更好的推断和更好的IntelliSense建议:
flattenArrayByKey<"anotherArray", number>(objectsWithNestedProperties, "anotherArray")
输入和输出的行为应该相同,但是如果您开始输入
type ArrayKeys<T> = { [K in keyof T]: T[K] extends any[] ? K : never }[keyof T];
function flattenArrayByKey<T extends Record<K, any[]>, K extends ArrayKeys<T>>(
array: T[],
prop: K
): T[K][number][] {
return array.reduce(
(arr, item) => [...arr, ...(item[prop] || [])],
[] as T[K][number][]
);
}
这将建议const result = flattenArrayByKey(objectsWithNestedProperties, "");
// put cursor here and get intellisense prompts (ctrl-spc) ---^
(现在是"arrayProperty"
)作为第二个参数,因为只有"anotherArray"
(和arrayProperty
)适合于这样的缩小。
希望再有帮助。祝好运!
答案 1 :(得分:0)
结果证明ESNext具有Array.flatMap
,完全可以满足我的需求。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
语法
var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) { // return element for new_array }[, thisArg])
callback
函数,它使用三个参数生成新Array的元素:
currentValue
数组中正在处理的当前元素。
index
(可选) 数组中正在处理的当前元素的索引。
array
(可选) 调用了数组映射。
thisArg
(可选) 执行回调时用作this
的值。
要使用它,我需要将esnext.array
添加到lib
中的tsconfig.json
中:
{
"compilerOptions": {
"lib": ["es2018", "dom", "esnext.array"]
}
}
它正是我想要的:
objectsWithNestedProperties.flatMap(obj => obj.arrayProperty)
// returns ['hello', 'world', 'nice', 'to', 'meet', 'you']
NB :IE,Edge和Samsung Internet不支持此功能。