// Provided input
const input: Input = {
hello: {
type: "string",
},
first: {
second: {
type: "number"
}
}
}
// Expected output
const output = {
hello: "some-string",
first: {
second: 42
}
}
// Function that processes the input and spits out the expected output
function processInput<T extends Input>(input: T): Output<T> {
// Some logic
}
I want to process the nested input
object using the processInput
function to generate an output that looks like the output
object. This can be simply done by checking if the type
property exists, etc.
But my problem is the writing a type Output for the output. I would like to precisely type the output according the the provided input.
This is what I came up with so far:
export type Property = { type: "string" } | { type: "number" };
export type Input = { [key: string]: Property | Input };
export type Output<T extends Input> = {
[Key in keyof T]:
T[Key] extends { type: "string" } ? string :
T[Key] extends { type: "number" } ? number :
T[Key] extends Input ? Output<T[Key]> :
never
};
When accessing the hello
property (for example, output.hello
), it's always of type never
. What's going wrong?
CodePudding user response:
If the input is dynamic, this is impossible.
TypeScript only runs at compile-time, so it can't infer which properties a dynamic object has, because that information doesn't exist yet.
If the object is static (unlikely in actually useful code), you can use captain-yossarian from Ukraine's solution:
export type Property = { type: "string" } | { type: "number" };
export type Input = { [key: string]: Property | Input };
export type Output<T extends Input> = {
[Key in keyof T]:
T[Key] extends { type: "string" } ? string :
T[Key] extends { type: "number" } ? number :
T[Key] extends Input ? Output<T[Key]> :
never
};
function processInput<T extends Input>(input: T): Output<T>
function processInput<T extends Input>(input: T) {
return null as any
}
const result = processInput({
hello: {
type: "string",
},
first: {
second: {
type: "number"
}
}
})