Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive Types in TypeScript

Tags:

typescript

Let's suppose we try to create HTML build helper

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

The type declaration for arguments of the build would be (actually it will be more complicated but let's consider just the simplest case)

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

Unfortunately id didn't works, because TypeScript complains

TS2456: Type alias 'Node' circularly references itself.

Is there any workaround?

like image 816
Alex Craft Avatar asked Dec 16 '17 03:12

Alex Craft


People also ask

Does TypeScript support recursion?

We have shown that, with those two rather simple transformations - making recursive function tail call recursive and trampolining, we can enjoy recursion even in TypeScript (Javascript) without worrying about our stack safety.

How do you write a recursive function in TypeScript?

Basically there are two ways to code recursive functions in TypeScript: First by directly calling the function from within itself and. Second by using an indirect call.

How do you define a recursive type?

In computer programming languages, a recursive data type (also known as a recursively-defined, inductively-defined or inductive data type) is a data type for values that may contain other values of the same type. Data of recursive types are usually viewed as directed graphs.

Should I use type or interface TypeScript?

The official Typescript documentation also says: ... we recommend using an interface over a type alias when possible. This also suggests that the type is more intended for creating type aliases than creating the types themselves.


2 Answers

Type aliases can't be circular, but interfaces can. This accomplishes what you want:

type MyTuple<T> = [string, { [key: string]: string }, T[]];
interface Node extends MyTuple<Node> { }
like image 82
Ryan Cavanaugh Avatar answered Sep 28 '22 17:09

Ryan Cavanaugh


This can now be done as of typescript 3.7: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#more-recursive-type-aliases

For example:

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

const nestedStringArray: NestedStringArray = [
  'hello',
  ['w', ['o', 'r', 'l'], 'd'],
];
like image 44
Ulad Kasach Avatar answered Sep 28 '22 16:09

Ulad Kasach