Home > Software design >  A recursive interface for a React Typescript component
A recursive interface for a React Typescript component

Time:11-16

The component is a breadcrumb, it must receive as props an object that contains a title and an url and also an option children node. The maximum depth should be 5, in this case this is a props example:

myProps = {
            title: "level 1",
            url: "/",
            children: {
                        title: "level 2"
                        url: "/level2"
                        children: { 
                                    title: "level 3"
                                    url: "level2/level3"
                                    children: {
                                                title: "level 4"
                                                url: "level2/level3/level4"
                                                children: {
                                                            title: "level 5"
                                                            url: "/level2/level3/level4/level5"
                                                          }
                                               }
                                  }
                       }
          };

But it can also have less nesting, for example:

myProps = {
            title: "title1"
            url: "/"
            children: null
          }

How should the interface look like?

Is this correct?

export interface MyProps {
  title: string;
  url: string;
  children: MyProps;
}

CodePudding user response:

You need to account for those without children, so

export interface MyProps {
  title: string;
  url: string;
  children?: MyProps | null;
}

CodePudding user response:

Your interface is a good start! If I get it right, MyProps.children is optional, right? In that case you can declare it like that:

export interface MyProps {
  title: string;
  url: string;
  children?: MyProps;
}

This allows you to leave out the property children during declaration of a variable of type MyProps and to explicitly assign it undefined:

const myProps: MyProps = {
  title: "title1",
  url: "/"
};

const otherProps: MyProps = {
  title: "title1",
  url: "/",
  children: {
    title: "title2",
    url: "/otherUrl"
  }
};

const yetOtherProps: MyProps = {
  title: "title1",
  url: "/",
  children: undefined
};

CodePudding user response:

If you know upfront the number of nested properties you can use this utility type:

export interface MyProps {
  title: string;
  url: string;
  children: undefined;
}

type Recursive<
  Length extends number,
  Counter extends number[] = [],
  Result = MyProps
  > =
  (Length extends Counter['length']
    ? Result
    : {
      [Prop in keyof MyProps]:
      (Prop extends 'children'
        ? (Length extends [...Counter, 1]['length']
          ? Recursive<Length, [...Counter, 1], undefined>
          : Recursive<Length, [...Counter, 1], Result>)
        : (Prop extends 'title'
          ? `${string} ${[...Counter, 1]['length'] extends string | number ? [...Counter, 1]['length'] : ''}`
          : MyProps[Prop])
      )
    })

// type Result = {
//     title: `${string} 1`;
//     url: string;
//     children: {
//         title: `${string} 2`;
//         url: string;
//         children: {
//             title: `${string} 3`;
//             url: string;
//             children: {
//                 title: `${string} 4`;
//                 url: string;
//                 children: {
//                     title: `${string} 5`;
//                     url: string;
//                     children: undefined;
//                 };
//             };
//         };
//     };
// }
type Result = Recursive<5>

Playground

Explanation

Recursive parameters: Length - the number of nested properties Counter - since it is impossible to make math operations in TS I'm using a tuple and increase the length every time by 1 [...Counter, 1] Result - straightforward - result :D

How does it work?

Each step starts with comparison of Length and Counter['length']. If Counter['length'] is equal desired number of nested properties - return Result.

Otherwise, iterate through each property of MyProps end each time when loop encounter children property - call it recursively with increased Counter.

I have added an extra logic for title property. Each title property has its own number.

That's all.

  • Related