类型 T 的交​​错数组的类型定义及其数组原型扩展

Type definition for a jagged array of type T and its array prototype extension

我正在尝试为附加到 Array.prototype 的 JavaScript 函数编写 Typescript 定义文件。

Array.js

/**
 * Flattens the array recursively.
 *
 * @example
 * [1, [2, 3]].flat() // => [1, 2, 3]
 *
 * @example
 * [[1, [2, 3], [4, [5]]], 6].flat() // => [1, 2, 3, 4, 5, 6]
 */
Array.prototype.flat = function () {
    return this.reduce((arr, val) => Array.isArray(val) ? arr.concat(val.flat()) : arr.concat(val), []);
}

flat() 适用于 Array<T|S>,其中 SArray<T|S> 和 returns Array<T>。也就是说,它有一个递归定义,并且所有数组都符合该定义,因为 [1, 2, 3].flat() 将只是 return 原始数组的副本。

我是 TypeScript 的新手,但我的理解是,为了获得 TypeScript 定义文件(即 IntelliSense)的好处,方法定义必须在 interface Array<T> 内。如果是这种情况,是否有办法为 Array<T> 的特殊版本对 T 施加约束?

如果不是,我如何定义一个接口,该接口将为每个数组选取并识别数组何时符合递归定义?

这不是一个完整的答案,但它确实帮助我们解决了大部分问题。这里是in the TypeScript Playground

type JaggedArrayItem<T> = T | JaggedArray<T>;

interface JaggedArray<T> extends Array<JaggedArrayItem<T>> { }

type FlatArray<T> = T extends JaggedArrayItem<infer U> ? U[] : T;

interface Array<T> {
  flat(this: JaggedArray<T>): FlatArray<T>;
}

Array.prototype.flat = function () {
  return this.reduce(
    (arr, val) => Array.isArray(val)
      ? arr.concat(val.flat())
      : arr.concat(val),
    []);
};

// Test

const myRecursiveArray: JaggedArray<number> = [
  10,
  [9],
  [
    [8],
    [
      [7],
    ]
  ],
];

const flattened: number[] = myRecursiveArray.flat();    
const flattenedToo: (string | number)[] = [1, 'two'].flat();

另见