Structural Typing
TypeScript es un sistema de tipo estructural. Un sistema
de tipo estructural significa que cuando se comparan los
tipos, TypeScript sólo tiene en cuenta los miembros en el
tipo.
Esto es en contraste con los sistemas de tipo nominal,
donde se pueden crear dos tipos pero no se pueden asignar
uno al otro. Véase example:nominal-typing
Por ejemplo, estas dos interfaces son completamente
transferibles en un sistema de tipo estructural:
// Si añadimos un tipo que estructuralmente contiene todos
los miembros de Ball (Bola) y Sphere (Esfera), entonces
también puede ser configurado para ser una bola o esfera.
interface Ball {
diameter: number;
}
interface Sphere {
diameter: number;
}
let ball: Ball = { diameter: 10 };
let sphere: Sphere = { diameter: 20 };
sphere = ball;
ball = sphere;
// Debido a que una bola no tiene una longitud, no puede ser
asignada a la variable `tube`. Sin embargo, todos los
miembros de Ball están dentro de Tube, y por lo
tanto puede ser asignada.
TypeScript está comparando cada miembro del tipo con los
demás para verificar su igualdad.
Una función es un objeto en JavaScript y se compara de
manera similar. Con un útil truco extra alrededor de los
parámetros:
interface Tube {
diameter: number;
length: number;
}
let tube: Tube = { diameter: 12, length: 3 };
tube = ball;
ball = tube;
// TypeScript permitirá que (number) sea igual a (number, boolean)
en los parámetros, pero no (number, boolean) -> (number)
TypeScript descartará el booleano en la primera
asignación porque es muy común que el código JavaScript
salte los parámetros de paso cuando no se necesitan.
Por ejemplo, el método forEach del arreglo tiene tres
parámetros, value, index y el arreglo entero - si
TypeScript no soportará el descarte de parámetros,
entonces tendrías que incluir todas las opciones para
hacer que las funciones coincidieran:
let createBall = (diameter: number) => ({ diameter });
let createSphere = (diameter: number, useInches: boolean) => {
return { diameter: useInches ? diameter * 0.39 : diameter };
};
createSphere = createBall;
createBall = createSphere;
// Los tipos de retorno se tratan como objetos, y cualquier
diferencia se compara con las mismas reglas de igualdad
de objetos de arriba.
[createBall(1), createBall(2)].forEach((ball, _index, _balls) => {
console.log(ball);
});
// Nadie necesita eso.
// Donde la primera asignación funciona (ambos tienen
diámetro) pero la segunda no (la bola no tiene color).
let createRedBall = (diameter: number) => ({ diameter, color: "red" });
createBall = createRedBall;
createRedBall = createBall;