Skip to content

Instantly share code, notes, and snippets.

@Fasteroid
Created June 12, 2024 14:30
Show Gist options
  • Save Fasteroid/8e4e193357bc98ba99814f9d5dadb8d2 to your computer and use it in GitHub Desktop.
Save Fasteroid/8e4e193357bc98ba99814f9d5dadb8d2 to your computer and use it in GitHub Desktop.
Ever needed to define a tree-like type in TypeScript with strict rules about what's on each level?
// PLEASE CREDIT EVERYONE IN HERE IF YOU USE THIS PLEASE AND THANKS 🙏🙏🙏
// https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
// These types let you do (buggy) arithmetic within typescript's type system
type BuildTuple<L extends number, T extends any[] = []> =
T extends { length: L } ? T : BuildTuple<L, [...T, any]>;
type Length<T extends any[]> =
T extends { length: infer L } ? L : never;
type Subtract<A extends number, B extends number> =
BuildTuple<A> extends [...(infer U), ...BuildTuple<B>]
? Length<U>
: never;
// https://stackoverflow.com/questions/59658536/how-to-write-an-invert-type-in-typescript-to-invert-the-order-of-tuples
// We use this to reverse the tuple so that `Types[0]` is the root of the tree (this is more intuitive)
type Reverse<Tuple> = Tuple extends [infer Head, ...infer Rest]
? [...Reverse<Rest>, Head] : [];
/**
* The most awesome tree structure you've ever seen!
* ```ts
const example: TypeSafeTree<[never, string]> = { // you can pass 'never' if you don't want a value at a level
children: [
{ value: "hello" }, // no need for children: undefined here, this type is smarter than that!
{ value: "world" }
]
};
* ```
* @author Fasteroid <https://github.com/Fasteroid/>
* @template Types - The types of the values at each level of the tree
*/
export type TypeSafeTree< Types extends any[], Level extends number = Subtract< Length<Types>, 1 > > =
(Level extends 0 ? {} : { children: TypeSafeTree<Types, Subtract<Level, 1>>[] }) &
(Reverse<Types>[Level] extends never ? {} : { value: Reverse<Types>[Level] })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment