Just to give a little bit of context: I'm building a quite complicated form with conditional required values that depend on what has been selected in previous inputs.
Therefore, I made the following object that tells whether an input should be required or not:
enum IssueType {
Error = "Error",
Advice = "Advice",
}
enum Category {
Software = "Software",
Hardware = "Hardware",
Other = "Other",
}
const inputNames = {
issueType: "issueType",
concerning: "concerning",
serialNumber: "serialNumber",
errorCode: "errorCode",
} as const;
const conditions: Conditions = {
[IssueType.Error]: {
~~~~~~~~~~~~~~~> Property 'Other' is missing in type ...
[Category.Software]: {
[inputNames.concerning]: true,
[inputNames.serialNumber]: true,
[inputNames.errorCode]: true,
},
[Category.Hardware]: {
[inputNames.concerning]: true,
[inputNames.serialNumber]: true,
[inputNames.errorCode]: true,
}
},
[IssueType.Advice]: {
[Category.Software]: {
[inputNames.concerning]: true,
[inputNames.serialNumber]: true,
[inputNames.errorCode]: true,
},
[Category.Hardware]: {
[inputNames.concerning]: true,
[inputNames.serialNumber]: true,
[inputNames.errorCode]: true,
},
[Category.Other]: {
[inputNames.concerning]: true,
[inputNames.serialNumber]: true,
[inputNames.errorCode]: true,
}
}
};
Now my question is what would the type (Conditions
in the snippet above) of conditions
look like. I have tried this:
type Conditions = {
[K in IssueType]: {
[K in IssueType extends IssueType.Error
? Exclude<Category, Category.Other>
: Category]: {
[K in Exclude<
keyof typeof inputNames,
typeof inputNames.issueType
>]: boolean;
};
};
};
but the Exclude
of Category.Other
doesn't work. It should only be a mandatory property if it's parent's object key is of type IssueType.Error
. What am I doing wrong here?
Also I want to avoid (if possible) Nullable Types like that for instance:
type Conditions = {
[K in IssueType]: {
[K in Category]?: {
[K in Exclude<
keyof typeof inputNames,
typeof inputNames.issueType
>]: boolean;
};
};
};
In the second level of the object, you should reference K
(from one level up) instead of IssueType
. To do this, you cannot name the key type with K
for all levels.
Here's one where I renamed K
's with A
, B
, and C
for clarity:
type Conditions = {
[A in IssueType]: {
[B in A extends IssueType.Error
? Exclude<Category, Category.Other>
: Category]: {
[C in Exclude<
keyof typeof inputNames,
typeof inputNames.issueType
>]: boolean;
};
};
};
Check the playground.