Reputation:
How can I dynamically assign a type to a generic class based on the type variable's property? For example
interface EntityErrors<T> {
[p in keyof T]?: string; // How can I make "string" dynamic? It needs to be a string for primitives (id, name), and an array of strings for the `teachers` array.
// I've tried the following, but it appears `teachers` is still resolving to `SimpleError` instead of `ArrayOfErrors`.
[p in keyof T]?: p extends [] ? ArrayOfErrors<p> : SimpleErrors;
// I've also tried `instanceof` and `typeof`, but I receive syntax errors.
[p in keyof T]?: p instanceof [] ? ArrayOfErrors<p>: SimpleErrors;
}
interface School {
id: string;
name: string;
teachers: Teacher[];
}
interface Teacher {
id: string;
name: string;
}
Because the School
error object looks like:
{
"id": "The input is invalid",
"name": "The input is invalid",
"teachers": [
{
"id": "The input is invalid",
"name": "The input is invalid"
},
{
"id": "The input is invalid",
"name": "The input is invalid"
}
]
}
Upvotes: 4
Views: 4494
Reputation: 249636
Based on your requirements, things will get a bit more complicated, as the errors type needs to be recursive. If we encounter a primitive array or a primitive property the property in the result type will be string. If we have an entity or an entity array we need to apply the type recursively to get the appropriate result.
To do this we need to use a mapped type. The the type of property will be T[P]
with P
beeing the property name
type EntityErrors<T> = {
[P in keyof T]?:ErrorProperty<T[P]>
}
type Primitive = number| string| Date | boolean
type ErrorProperty<T> =
T extends Primitive ? string :
T extends Array<Primitive> ? string[] :
T extends Array<infer U> ? Array<EntityErrors<U>> :
EntityErrors<T>;
interface School {
id: string;
name: string;
teachers: Teacher[];
}
interface Teacher {
id: string;
name: string;
}
let e:EntityErrors<School> = {
"id": "The input is invalid",
"name": "The input is invalid",
"teachers": [
{
"id": "The input is invalid",
"name": "The input is invalid"
},
{
"id": "The input is invalid",
"name": "The input is invalid"
}
]
}
Upvotes: 0
Reputation: 887453
p
is a string type with the name of the property.
You need to check the type of the property within your class:
[p in keyof T]?: T[p] extends [] ? ArrayOfErrors<T[p]>: SimpleErrors;
Upvotes: 6