typescript - Nombre de propiedad condicional en interfaz de TypeScript dependiendo del tipo pasado
El título suena confuso, pero aquí está la esencia.
Tengo una interfaz User que puede o no tener algunas propiedades dependiendo de dónde se obtenga. Esto es lo que quiero decir: (observa las propiedades opcionales role y client_details)
export interface User {
id: string;
first_name: string;
last_name: string;
email: string;
// -- One of these in undefined depending on fetch location
role?: Role;
client_details?: ClientDetails;
}
El enfoque anterior funciona, sin embargo tener un valor indefinido cada vez no se ve muy bien. Sería más ordenado si pudiera hacer esto:
export interface User<ExtraType = Role | ClientDetails> {
id: string;
first_name: string;
last_name: string;
email: string;
// -- Dynamic property name instead, much cleaner approach
[ExtraType === Role ? 'role' : 'client_details']: ExtraType;
}
Esto no funciona y genera un montón de errores, principalmente No se puede que un nombre de propiedad computada haga referencia a un parámetro de tipo de su tipo contenedor.
Soy consciente de que puedo simplemente crear una propiedad estática extra y simplemente usarla cada vez, pero quería que el nombre de la propiedad tuviera algo de sentido. ¿Es esto factible en absoluto? ¡Gracias!
Respuesta #1
Lo que necesitas aquí es una unión disjunta de tipos. En tu caso, se puede hacer así:
interface UserBase {
id: string;
first_name: string;
last_name: string;
email: string;
}
interface UserWithRole extends UserBase {
role: Role;
client_details?: undefined;
}
interface UserWithDetails extends UserBase {
client_details: ClientDetails;
role?: undefined;
}
export type User = UserWithRole | UserWithDetails;
Ahora, dondequiera que tengas un valor del tipo User, puedes comprobarlo así:
function test(user: User) {
if (user.role) {
// here typescript knows that user is of type UserWithRole
} else {
// and here it knows that user is of type UserWithDetails
}
}
He agregado una declaración de propiedad faltante (property?: undefined) a ambos tipos para que TypeScript no se queje de que User no siempre tiene la propiedad .role; puedes eliminarla y ver el error en la línea if (user.role).
Aquí está el ejemplo completo
