Pesquisa de site

typescript - Como é possível "duck type" um objeto quando a Classe possui propriedades encapsuladas?


Eu estava me perguntando se é uma boa prática usar accessors em TS, e enquanto eu testava casos, percebi que fazer isso faz você perder o "recurso" de "duck-typing".
Isso é por design para impedir que desenvolvedores cometam erros de digitação indesejados ou estou perdendo alguma coisa?

    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 = ''
    }

Isso deveria ser uma atribuição válida, mas ele me mostra o seguinte erro:

Propriedade 'hoverTitle' está ausente no tipo '{ title: string; _title: string; summary: string; _summary: any; }', mas é obrigatória no tipo 'BlogPost'.

Quando tento adicionar essas propriedades, como elas são privadas, aparece este erro:

Tipo '{ _hoverTitle: any; _summary: any; _title: any; hoverTitle: any; summary: any; title: any; }' não é atribuível ao tipo 'BlogPost'. Propriedade '_title' é privada no tipo 'BlogPost', mas não no tipo '{ _hoverTitle: any; _summary: any; _title: any; hoverTitle: any; summary: any; title: any; }'.

Isso é intencional ou estou perdendo algo?

Aqui está uma visualização ao vivo do erro

Eu acho que esta é uma boa maneira de lidar com o problema! visualização

Basta fazer a classe implementar uma interface e então usar a interface para "duck typing"... desta forma não importa se a classe tem campos privados encapsulados porque você está digitando como a interface.

Isso veio da resposta de @Titian Cernicova-Dragomir...

Resposta #1

Privates fazem a classe se comportar de forma nominal, não é possível criar um alias de uma classe com campos privados. Por outro lado, podemos removê-los usando Pick para obter apenas as propriedades públicas:

let blogPostItem: Pick<BlogPost, keyof BlogPost>;

blogPostItem = {
    hoverTitle: '',
    summary: '',
    title: ''
}

Você também pode usar uma declaração de tipo para ignorar os erros.

Resposta #2

Para emendar a resposta de @Titian Cernicova-Dragomir,

Os soldados fazem a classe se comportar normalmente.

Note que ele diz "comporte-se nominalmente", mas não "nominal".

O tipo de Classe no TypeScript inclui campos privados e os compara estruturalmente. É uma escolha de design feita pela equipe do TS para evitar acesso acidental ou substituição dos campos privados.

Isso realmente cria muita confusão e pontos de dor, e uma das principais forças motivadoras para mim fazer programação sem classes em TS.

O Pick<> é um truque legal para contornar essa "limitação".

Artigos relacionados