typescript - ¿Cómo es posible hacer 'duck typing' a un objeto cuando la clase tiene propiedades encapsuladas?
Me preguntaba si es una buena práctica usar accesores en TS, y estaba probando casos y noté que al hacerlo, se pierde la "característica" de "duck-typing".
¿Es por diseño para evitar que los desarrolladores cometan errores de tipeo no deseados o me estoy perdiendo de algo?
class BlogPost {
constructor(private _title: string, private _summary: string,
private _hoverTitle?: string) {
}
public get title(): string {
return this._title;
}
public set title(value: string) {
this._title = value;
}
public get summary(): string {
return this._summary;
}
public set summary(value: string) {
this._summary = value;
}
public get hoverTitle(): string {
return this._hoverTitle;
}
public set hoverTitle(value: string) {
this._hoverTitle = value;
}
}
let blogPostItem: BlogPost;
blogPostItem = {
hoverTitle = '',
summary = '',
title = ''
}
Esto debería ser una asignación válida, pero me muestra el siguiente error:
La propiedad 'hoverTitle' falta en el tipo '{ title: string; _title: string; summary: string; _summary: any; }', pero es requerida en el tipo 'BlogPost'.
Cuando intento agregar estas propiedades, como son privadas muestra este error:
El tipo '{ _hoverTitle: any; _summary: any; _title: any; hoverTitle: any; summary: any; title: any; }' no se puede asignar al tipo 'BlogPost'. La propiedad '_title' es privada en el tipo 'BlogPost' pero no en el tipo '{ _hoverTitle: any; _summary: any; _title: any; hoverTitle: any; summary: any; title: any; }'.
¿Esto es intencional o me estoy perdiendo de algo?
Aquí hay una vista previa en vivo del error
¡Creo que esta es una buena manera de manejar el problema! vista previa
Solo haz que la clase implemente una interfaz y luego usa la interfaz para el "duck typing"... de esta manera no importa si la clase tiene campos privados encapsulados porque estás tipeando como la interfaz.
Esto vino de la respuesta de @Titian Cernicova-Dragomir...
Respuesta #1
Los privados hacen que la clase se comporte nominalmente, no es posible crear un alias de una clase con campos privados. Por otro lado, podemos eliminarlos utilizando Pick para obtener solo las propiedades públicas:
let blogPostItem: Pick<BlogPost, keyof BlogPost>;
blogPostItem = {
hoverTitle: '',
summary: '',
title: ''
}
También puedes usar una aserción de tipo para ignorar los errores.
Respuesta #2
Para enmendar la respuesta de @Titian Cernicova-Dragomir,
Los soldados rasos hacen que la clase se comporte nominalmente.
Observa que él dice "comportarse nominalmente", pero no "nominal".
El tipo de Clase en TypeScript incluye campos privados y los compara estructuralmente. Es una elección de diseño hecha por el equipo de TS para evitar el acceso accidental o la sobrescritura de los campos privados.
Realmente crea mucha confusión y puntos dolorosos, y una de las principales fuerzas motivadoras para mí para hacer programación sin clases en TS.
El Pick<> es un buen truco para sortear esta "limitación".
