I want to create an object which can have either primitives or objects like itself as properties. I mean something like that would be wrong:
const obj: DesiredType = {
correctProp1: 'string',
correctProp2: 123,
correctProp3: true,
wrongProp4: [1, 2, 3],
prop5: {
wrongProp1: () => {}, // Is neither an object nor a primitive
wrongProp2: [1, 2, 3], // Same
correctProp3: 'other string'
}
}
I don't want to just use Record<string, any>
, because this way anything can be put there (function, array, etc). Using something like following:
Record<string, string | number | boolean | Record<string, any>>
would also be bad, because anything can appear on the second level
I have tried this:
type PrimitiveOrObject = string | number | boolean | Record<string, PrimitiveOrObject>; // ts(2456) type
DesiredType = Record<string, PrimitiveOrObject>;
But I get error ts(2456): Type alias "PrimitiveOrObject" circularly references itself.
So is there a way to create a type alias for objects which contain either primitives or objects like itself?
You can't use a type alias generically in the same definition that creates it. But you can use it in object type literals, so if we add a little bit of indirection, we can get the recursion you want.
type PrimitiveOrObject =
string | number | boolean | { [key: string]: PrimitiveOrObject };
The { [key: string]: PrimitiveOrObject }
syntax is called an index signature. For the key type of string
, it's equivalent to Record
(see this question for details), but it has the benefit of being inside an object literal and thus not subject to the recursion restriction you've run afoul of.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With