0

This is a follow-up of Interface Depending on the Types of a Recursive Property

Sorry if it looks like "write my code" questions, it's surely not meant to be something like that! I'm just getting started with advanced typings and I find it hard to grasp the possibilities I have to express types. So please bear with me :)

In my code I want to convert an object into a tree structure. The code is already doing that, but I want the types to reflect that properly. The code traverses each property of an object (or items if array) and turn them into nodes.

See Stackblitz for detailed example

My current approach:

interface Node<Type, Children> {
  value: Type,
  children: Children[],
}

function treeOf<T>(
  value: T,
): Node<
  T,
  {
    [K in T]: Node<T[K], any[]>[]
  },
> 

... gives me a TypeScript error:

Type 'Node<{ [x: string]: T[any]; }, any[]>' does not satisfy the constraint 'Node<unknown, any[]>[]'.
  Type 'Node<{ [x: string]: T[any]; }, any[]>' is missing the following properties from type 'Node<unknown, any[]>[]': length, pop, push, concat, and 26 more.

... and it also cannot handle arrays properly I think, as it considers an array's properties ("push", "pop", ...) instead of its items.

I also tried

function treeOf<T>(
  value: T,
): Node<
  T,
  Node<
    {
      [K in T]: T[K];
    },
    any[]
  >
> {

... but to no avail.

Again I don't know if this is possible with TypeScript as well, or if I am requesting to much now. But maybe someone can tell me :)

Stackbitz

https://stackblitz.com/edit/typescript-gb9bco?file=index.ts

jlang
  • 929
  • 11
  • 32
  • Could you please share code of your treeOf method? Or maybe share a small fiddle? Sorry, it is a little hard to understand the nature of your output tree. Like why result.children[1]; should be Node<[number, string], [Node, Node]> ? Is index of children a level of a tree? – Bibipkins Sep 18 '20 at 09:16
  • Sure. will update soon – jlang Sep 18 '20 at 09:27
  • Updated it :) And yes, index is of children – jlang Sep 18 '20 at 10:23
  • The obvious problem I see here is that there's no ordering on object keys. TS can't convert `{a: string, b: number}` into the tuple `[{name: "a", value: string}, {name: "b", value: number}]` because it could also be `[{name: "b", value: number}, {name: "a", value: string}]`. If you're happy with `Array<{name: "a", value: string} | {name: "b", value: number}>` that's fine, but it doesn't guarantee that each element exists exactly once. And having [all possible tuples](https://stackoverflow.com/questions/58194653/use-tuple-instead-of-array-of-union-within-type) is very taxing on the compiler. – jcalz Sep 18 '20 at 15:15
  • So what type do you expect to see? What type would you like the compiler to think the children property of `treeOf({a: "", b: 0})` is? I've thrown [this](https://tsplay.dev/KN7yrW) or [this](https://tsplay.dev/kNr4VW) together but I don't know if this is what you're looking for. No matter what the object-keys-to-array transformation will either be lossy, complicated, annoying, or all three. – jcalz Sep 18 '20 at 15:56
  • Oh okay, yes that's indeed really hard to read and/or use. Then I think I wanted too much in this case. For `treeOf({a: "", b: 0})` I would like to get as return type "{ name: string; value: {a:"", b: 0}, children: [ {name: string, value: string, children: any[] }, {name:string, value: number; children: any[] ] }`, or maybe `unknown[]` instead of `any[]` or simply `[]` for children – jlang Sep 18 '20 at 16:37

0 Answers0