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.