javascript - Typescript: Malentendido sobre el tipeo de pato
Estoy estudiando TypeScript leyendo manuales y documentación. Y solo tengo curiosidad sobre cómo funciona el Duck Typing en TypeScript.
Por ejemplo, este código proporciona un error de tipo (usando el Playground oficial de Typescript)
interface Point {
x: number;
y: number;
}
const p: Point = {
x: 1,
y: 2,
z: 3
}
function printPoint(p: Point) {
console.log(p.x + p.y);
}
printPoint(p);
pero este código no proporciona error de tipo
interface Point {
x: number;
y: number;
}
const p = {
x: 1,
y: 2,
z: 3
}
function printPoint(p: Point) {
console.log(p.x + p.y);
}
printPoint(p);
Creo que el problema está relacionado con el Tipado de Pato de Typescript, pero no pude entender por qué el sistema de tipos del argumento y el sistema de tipos de la constante funcionan de manera diferente.
¿Entendí mal lo del Duck Typing? const p contiene x, y, así que creo que const p: Point debería funcionar
Respuesta #1
Typescript impone diferentes niveles de rigor dependiendo de lo que estés haciendo. Cuando creas una variable con un tipo explícito, Typescript es muy estricto sobre lo que debe estar presente, no permitiendo propiedades adicionales. Una propiedad extra probablemente sea un error en tu código, ya que estás creando un valor y luego asignando inmediatamente un tipo que hace que ese valor sea inaccesible. Por lo tanto, la estricta vigilancia adicional te ayuda a detectar tales errores.
Cuando intentas asignar una variable a otra, incluido pasar una variable a una función, TypeScript realiza una verificación más flexible. Las dos variables solo necesitan ser compatibles entre sí, lo que más o menos significa que deben tener al menos las propiedades listadas con los tipos correctos, pero está bien si también tienen propiedades adicionales. Este nivel más flexible de verificación es parte de la forma en que TypeScript soporta subtipos y subclases. Deberías poder pasar una subclase en donde se requiere una clase base (el principio de sustitución de Liskov), pero la subclase a menudo tendrá propiedades adicionales.
Consulta este enlace para más información sobre compatibilidad de tipos: https://www.typescriptlang.org/docs/handbook/type-compatibility.html
Respuesta #2
El primer código mostró un TypeError porque la interfaz Point no tiene un miembro z. El segundo no tenía error de tipo, porque en la función, todas las propiedades referenciadas (x y y) existen en el tipo Point. Esto se debe a Duck Typing y a que se acepta como un Point o no, porque el miembro z no es referenciado. Dentro de la función, si intentas usar p.z, obtendrás un error de tipo.