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>
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.