Los tipos de intersección con interfaces no logran generar un error de TypeScript.
Al mezclar tipos TypeScript con interfaces en una intersección, parece que pierdo el comportamiento más estricto de las interfaces en mi código. Quiero poder componer tipos usando intersecciones (para poder limitar un tipo en instancias específicas), pero quiero poder mantener la precisión de las interfaces.
Tome este código:
type Vehicle = {
name: string
properties: Record<string, unknown="">
}
interface CarProperties {
electric?: boolean
}
type Car = Vehicle & {
name: 'car'
properties: CarProperties
}
const car: Car = {
name: 'car',
properties: {
electric: false,
someOther: 'bs' // <= Quiero que esto genere un error de TS
}
}
Como CarProperties es una interfaz, esperaría que no se permita la inclusión de la clave someOther.
¿Por qué no es así? ¿Y cómo se lograría lo mismo de otra manera?</string,>
davy.ai
La razón por la cual esto no es el caso es porque cuando se mezcla un tipo y una interfaz en una intersección, el tipo tiene prioridad sobre la interfaz. Esto significa que el tipo
Car
permitirá cualquier propiedad que esté definida en el tipoVehicle
, independientemente de lo que esté definido en la interfazCarProperties
.Para lograr el comportamiento deseado, puedes utilizar un tipo mapeado en lugar de una intersección. Los tipos mapeados te permiten crear un nuevo tipo basado en un tipo existente, pero también te permiten especificar restricciones adicionales. En este caso, puedes utilizar un tipo mapeado para crear un tipo
Car
basado en el tipoVehicle
, pero que también requiere que el campoproperties
sea de tipoCarProperties
:typescript
type Car = {
[P in keyof Vehicle]: Vehicle[P] extends Record<string, unknown> ? {
name: 'car'
properties: CarProperties
} : Vehicle[P]
}
Ahora, cuando intentas asignar un valor al tipo
Car
, el compilador lanzará un error si el campoproperties
no coincide con la interfazCarProperties
:typescript
const car: Car = {
name: 'car',
properties: {
electric: false,
someOther: 'bs' // <-- Error de TS: La propiedad 'someOther' no existe en el tipo 'CarProperties'. } }