TypeScript中的递归类型

Ale*_*hin 5 typescript

假设我们尝试创建HTML构建帮助器

build([
  'html', { lang: 'en' }, [
    ['head', [
      ['title', 'Hello, world!']
    ]
  ]
])
Run Code Online (Sandbox Code Playgroud)

the参数的类型声明build将是(实际上会更复杂,但让我们考虑最简单的情况)

type Node = [string, { [key: string]: string }, Node[]]
Run Code Online (Sandbox Code Playgroud)

不幸的是,id无效,因为TypeScript抱怨

TS2456: Type alias 'Node' circularly references itself.
Run Code Online (Sandbox Code Playgroud)

有什么解决方法吗?

Ula*_*ach 13

这现在可以从 typescript 3.7 开始:https : //www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#more-recursive-type-aliases

例如:

type ValueOrArray<T> = T | ValueOrArray<T>[];
type NestedStringArray = ValueOrArray<string>;

const nestedStringArray: NestedStringArray = [
  'hello',
  ['w', ['o', 'r', 'l'], 'd'],
];
Run Code Online (Sandbox Code Playgroud)

  • 哦,有趣。这听起来像是一个很好的候选堆栈溢出问题 (2认同)

JΛY*_*ÐΞV 10

据我所知,这里的所有答案都已过时。在 2022 年,我只是使用以下内容递归扫描目录并保存扫描返回的所有文件和目录:

    type AbstractDirectory = {
      pathname: string;
      files: string[];
    };

    type AbstractFileTree = string | string[] | {
      [ key: string ]: AbstractFileTree;
      dirpath: string;
      filepaths: string[];
    };
Run Code Online (Sandbox Code Playgroud)

也许递归类型最常见的需求是需要使用真正的 JSON 类型。JSON 是一种可以按照程序员需要的递归格式。

旧版本的 TypeScript (pre v3.7输入 JSON,如下所示:

    type Json =  string | number | boolean | 
                 null | JsonObject | JsonArray;

    interface JsonObject {
        [property: string]: Json;
    }

    interface JsonArray extends Array<Json> {}
Run Code Online (Sandbox Code Playgroud)

以下代码片段演示了“v3.7发行说明”中包含的一个很好的示例,这对于您可能正在执行的任何递归键入来说都是一个很好的解决方案。

截至v3.7或更新版本,以下内容是有效的 TypeScript:

type Json =
  | string
  | number
  | boolean
  | null
  | { [property: string]: Json }
  | Json[];

Run Code Online (Sandbox Code Playgroud)

这两个示例都是递归的,但后者更清晰、更易读、编写更快、更容易记住,并且是 JSON 的更好抽象表示。


Rya*_*ugh 9

类型别名不能是循环的,但是接口可以。这完成了您想要的:

type MyTuple<T> = [string, { [key: string]: string }, T[]];
interface Node extends MyTuple<Node> { }
Run Code Online (Sandbox Code Playgroud)


Dan*_*ald 5

很快,使用递归类型引用将变得更加容易https://github.com/microsoft/TypeScript/pull/33050

  • 这已合并,问题中的代码现在可以正常工作。 (3认同)