I want to declare the type for this kind of recursive object where name and link is a mandatory field
{
1: {
name: 'Youtube',
link: '/inventory/youtube',
1: {
name: 'home',
link: '/inventory/youtube/home'
}
},
2: {
name: 'Network Infrastructure',
link: '/inventory/network-infrastructure',
}
}
I have tried to do like this but getting error (Property 'name' of type 'string' is not assignable to 'string' index type 'propTypes'),
type propTypes = {
name: string;
link: string;
[key: string | number]: propTypes
};
If the unknown keys are any possible string at all, then what you want isn't really possible in TypeScript at the moment.
An string
index signature like {[key: string]: PropTypes}
means: if a property with a key of type string
exists, then it must have a value of type PropTypes
. But that means the link
and name
properties would also need to be of type PropTypes
and not string
like you want. That's where the error comes from.
You might want to say "every string
key except "link"
and "name"
should have a value of type PropTypes
. But there's currently no way to express that. There's a longstanding open issue at microsoft/TypeScript#17867 asking for such "hybrid" or "rest" index signatures. Who knows when or if something like that will ever be implemented. For now, there's no specific type in TypeScript that works this way.
There are various workarounds but they are all somewhat complicated. See How to define Typescript type as a dictionary of strings but with one numeric "id" property for an overview of the different possible approaches there.
However, in your case it seems that the unknown keys are specifically numeric strings like "1"
or "2"
and not arbitrary strings. In this case, you could use a number
index signature instead:
type PropTypes = {
name: string;
link: string;
[key: number]: PropTypes // okay
};
This is all right because "name"
and "link"
are not numeric strings. It's no longer a contradiction to say that the name
and link
properties should have string
values, while all numeric-like properties should have PropTypes
values. And thus your recursive object meets this definition:
const prop: { [key: number]: PropTypes } = {
1: {
name: 'Youtube',
link: '/inventory/youtube',
1: {
name: 'home',
link: '/inventory/youtube/home'
},
2: {
name: 'explore',
link: '/inventory/youtube/explore',
1: {
name: 'Indias Factory Customisation',
link: '/inventory/youtube/Indias-first-Factory-Customisation'
},
2: {
name: 'YouTube Mix',
link: '/inventory/youtube/YouTube-Mix'
}
}
},
2: {
name: 'Network Infrastructure',
link: '/inventory/network-infrastructure',
}
};
Note that prop
is not of type PropTypes
, because it lacks the name
and link
properties. But since each property and nested subproperty does have those properties, you can say that prop
is of type {[key: number]: PropTypes}
.