用于任何数组的Typescript接口,但不是其他数组



flatten接受任意数据类型的数组,并生成一个嵌套数组平坦化的数组。

例如,[{}, 'hello', 2, [3, ['ay'], 'oi oi']变为[{}, 'hello', 2, 3, 'ay', 'oi oi'],[[[[5]]]]变为[5]

我需要一个接口来描述这样一个函数。我开始写它的时候认为它会很简单,但后来我坚持描述一个数组,除了其他数组。

interface Flatten {
(any[]): ...?
}

欢迎有任何想法,谢谢:))

在TS 4.5(夜间版本)中是可行的,但不是以您期望的方式。

多亏了可变元组类型,你可以这样做:


type Reducer<
Arr extends Array<unknown>,
Result extends Array<unknown> = []
> =
(Arr extends []
? Result
: (Arr extends [infer H, ...infer Tail]
? (H extends Array<any>
? Reducer<[...H, ...Tail], Result> : Reducer<Tail, [...Result, H]>) : never
)
)
// [1,2,3]
type Result = Reducer<[[[1], [[[[[[[2]]]]]]]], 3]> 
// [1, 2, 3, 4, 5, 6]
type Result2 = Reducer<[[[[[[[[[1]]]]]]]],[[[[[[2,3,4]]]],[[[[5,6]]]]]]]> 

我如何使用它作为函数返回值类型?

为了与函数一起使用,您需要将参数转换为不可变数组:

type Reducer<
Arr,
Result extends ReadonlyArray<unknown> = []
> = Arr extends ReadonlyArray<unknown> ?
(Arr extends readonly []
? Result
: (Arr extends readonly [infer H, ...infer Tail]
? (H extends ReadonlyArray<any>
? Reducer<readonly [...H, ...Tail], Result> : Reducer<Tail, readonly [...Result, H]>) : never
)
) : never

const flatten = <
Elem,
T extends ReadonlyArray<T | Elem>
>(arr: readonly [...T]): Reducer<T> =>
arr.reduce((acc, elem) =>
Array.isArray(elem)
? flatten(elem) as Reducer<T>
: [...acc, elem] as Reducer<T>,
[] as Reducer<T>
)

const result = flatten([[[[[[1]]], 2], 3]] as const)

游乐场

你还应该为reduce方法添加第二个参数。

你可以在我的文章中找到更多的解释。

如果您想更好地理解Reducer实用程序类型是如何工作的,请参见以下示例:

const Reducer = <T,>(Arr: ReadonlyArray<T>, Result: ReadonlyArray<T> = [])
: ReadonlyArray<T> => {
if (Arr.length === 0) {
return Result
}
const [Head, ...Tail] = Arr;
if (Array.isArray(Head)) {
return Reducer([...Head, ...Tail], Result)
}
return Reducer(Tail, [...Result, Head])
}

如果您知道flat array应该返回的所有数据类型,您可以像下面这样定义它:

type Flat = string|number|FlatObj;
type FlatArr = Array<Flat>;
type FlatObj = {[key: string]: Flat|FlatArr};

在您的示例中,您嵌套了空对象,所以我假设您希望它也只包含平面数组,FlatObj是它的定义。

现在,如果你尝试在任何FlatArr变量中分配嵌套数组,它应该会报错。

游乐场链接

如果你正在寻找类型保护,这里有一个FlatArrFlatObj的例子:

type AnyObj = {[key: string]: any};
function isFlatObj(obj: AnyObj): obj is FlatObj {
let flat = true;
for (const key in obj) {
if (Array.isArray(obj[key]) && !isFlatArr(obj[key])) flat = false;
else if (typeof obj[key] === 'object' && !isFlatObj(obj[key])) flat = false;
}
return flat;
}
function isFlatArr(arr: any[]): arr is FlatArr {
let flat = true;
arr.map((item) => {
if (Array.isArray(item)) flat = false;
else if (typeof item === 'object' && !isFlatObj(item)) flat = false;
});
return flat;
}
要创建FlatArr,可以为它定义一个函数。我在下面做了两个函数。一个使数组变平,另一个确保对象数组也变平:
const flattenArr = (arr: any[]): FlatArr => {
const flatArr: FlatArr = [];
for (const item of arr) {
if (Array.isArray(item)) flatArr.push(...flattenArr(item));
else if (typeof item === 'string') flatArr.push(item);
else if (typeof item === 'number') flatArr.push(item);
else if (typeof item === 'object') flatArr.push(flattenObj(item));
}
return flatArr;
}
const flattenObj = (obj: AnyObj): FlatObj => {
let flatObj: FlatObj = {};
for (const key in obj) {
if (Array.isArray(obj[key])) flatObj[key] = flattenArr(obj[key]);
else if (typeof obj[key] === 'string') flatObj[key] = obj[key];
else if (typeof obj[key] === 'number') flatObj[key] = obj[key];
else if (typeof obj[key] === 'object') flatObj[key] = flattenObj(obj[key]);
}
return flatObj;
}

最新更新