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?
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.
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.
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.
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.
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> { }
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'],
];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With