Suppose one has a recursive type, A
:
type A = {
id: number
children?: { [k: string] : A }
}
So an example of A
would be:
const a: A = { id: 1, children: {
foo: { id: 2, children: {
fizz: { id: 4 }
} },
bar: { id: 3, children: { ... } }
} }
The type of a
is exactly A
, so when referencing a
elsewhere, there is no guidance as to what the children of all the nodes within a
are.
To solve this, one can write a function that creates an object of A
. It simply returns the provided a
parameter value:
const createA = <T extends A>(a: T): T => a
createA
now solves the above limitation. One is now both provided with intellisense in how to create an A
(as a parameter to createA
), and the output of the function will have intellisense about the children of all the nodes within a
. For example:
const a = createA({ ... })
// (alias) createA<{ <-- The intellisense for a shows the children
// id: number
// children: {
// foo: {
// id: number
// children: { ... }
// }
// ...
// }
// }>)
const childNode = a.children.notFoo // <-- Fails linting, since a.children.notFoo is invalid
const anotherChildNode = a.childen. // <-- Intellisense shows 'foo' and 'bar' as available
Say we modify createA
to add on a property, say path
, to each node in the provided a
(the implementation is irrelevant), resulting in the following output:
const createModifiedA = (a: A) => { ... }
// { id: 1, path: '', children: {
// foo: { id: 2, path: '/foo', children: {
// fizz: { id: 4, path: '/foo/fizz' }
// } },
// bar: { id: 3, path: '/bar', children: { ... } }
// } }
I am wondering if it is possible, and if so, how, one would achieve the same end result as createA
but for createModifiedA
, keeping the intellisense for the all the children within all the nodes in the provided a
, I.e.:
const modifiedA = createModifiedA({ ... })
// (alias) createModifiedA<{ <-- Intellisense for modifiedA still shows all the children
// id: number
// path: string
// children: {
// foo: {
// id: number
// path: string
// children: { ... }
// }
// ...
// }
// }>)
const childNode = a.children.notFoo // <-- Fails linting, since a.children.notFoo is invalid
const anotherChildNode = a.childen. // <-- Intellisense *still* shows 'foo' and 'bar' as available
Edit 1 (sno2 answer)
Clarification: modifiedA
should have the intellisense just like createaA
that shows the available children at each node.
Edit 2
Improved wording.