TypeScript 中的递归类型

问题描述 投票:0回答:4

假设我们尝试创建 HTML 构建助手

build([
  'html', { lang: 'en' }, [
    ['head', [
      ['title', 'Hello, world!']
    ]
  ]
])

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

type Node = [string, { [key: string]: string }, Node[]]

不幸的是它不起作用,因为 TypeScript 抱怨

TS2456: Type alias 'Node' circularly references itself.

有什么解决办法吗?

typescript
4个回答
43
投票

类型别名不能是循环的,但接口可以。这实现了你想要的:

type MyTuple<T> = [string, { [key: string]: string }, T[]];
interface Node extends MyTuple<Node> { }

36
投票

现在可以从 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'],
];

10
投票

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

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

    type AbstractFileTree = string | string[] | {
      [ key: string ]: AbstractFileTree;
      dirpath: string;
      filepaths: string[];
    };

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

旧版本的 TypeScript (之前的

v3.7
输入 JSON,如下所示:

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

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

    interface JsonArray extends Array<Json> {}

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

v3.7

 或更高版本开始,以下内容是有效的 TypeScript:

type Json = | string | number | boolean | null | { [property: string]: Json } | Json[];
这两个示例都是递归的,但后者更清晰、更易读、编写更快、更容易记住,并且是对 JSON 的更好抽象表示。


8
投票
很快,递归类型引用就会变得更加容易

https://github.com/microsoft/TypeScript/pull/33050

© www.soinside.com 2019 - 2024. All rights reserved.