Is it possible to assert properties of an object based on another property within that same object?
But how can I infer the types for values
based on the value of type
property?
type StepKeys = "Test1" | "Test2";
interface objectMap {
"Test1": {
name: string
},
"Test2": {
age: number
}
};
interface Step<T extends StepKeys = StepKeys> {
type: T;
value: objectMap[T]
};
const steps: Record<string, Step> = {
"Step1": {
type: "Test1",
value: {
}
}
}
Here types for values
are a union of { name: string; } | { age: number; }
.
Is it possible to infer it's possible values?
CodePudding user response:
Hi should you want to effectively discriminate this union, the type parameter should not be a union, instead seek to "push" the union one type up. This is because we want each Step
type to have it's own unique type parameter, instead of the union of possible type parameters. So a small change, but accomplishes what you want.
const steps: Record<string, Step<'Test1'> | Step<'Test2'>> = {
"Step1": {
type: "Test1",
value: {
// infer ?
age: 11,
// ^^^ correctly throws error
// Object literal may only specify known properties, and 'age' does not exist in type '{ name: string; }'.(2322)
name: 'test',
}
}
}
Using an indexed access map type you can create a discriminated union automatically if there are a lot more key/value pairs.
type Steps = Record<string, {
[key in StepKeys]: Step<key>
}[StepKeys]>
CodePudding user response:
The only way to achieve what you want isn't really good but it works. The problem is that you have to manually enter every key (which makes it impossible to make it generic or scalable).
interface PeoplePropsMap {
withName: {
name: string
},
withAge: {
age: number
}
};
type People =
{ type: 'withName', value: PeoplePropsMap['withName'] } |
{ type: 'withAge', value: PeoplePropsMap['withAge'] }
const steps: Record<string, People> = {
john: {
type: 'withAge',
value: {
age: 10
}
}
}