【问题标题】:How is it possible to "duck type" an object when the Class has encapsulated properties?当类具有封装属性时,如何“躲避类型”对象?
【发布时间】:2019-06-15 18:37:50
【问题描述】:

我想知道在 TS 中使用访问器是否是一种好习惯,我是否正在测试用例,我注意到这样做会让你失去“鸭子打字”的“功能”。
是为了防止开发人员不必要的错误输入而设计的吗 还是我错过了什么?


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

这应该是一个有效的分配,但它显示了以下错误:

类型'{ title: string; 中缺少属性'hoverTitle'; _title:字符串;摘要:字符串; _摘要:任何; }' 但在 'BlogPost' 类型中是必需的。

当我尝试添加这些属性时,由于它们是私有的,它会显示此错误:

输入 '{ _hoverTitle: any; _摘要:任何; _title:任何;悬停标题:任何;摘要:任何;标题:任何; }' 不可分配给类型 'BlogPost'。 属性“_title”在“BlogPost”类型中是私有的,但在“{ _hoverTitle: any; _摘要:任何; _title:任何;悬停标题:任何;摘要:任何;标题:任何; }'。

这是有意为之还是我遗漏了什么?

Here is a live preview of the error


我认为这是处理问题的好方法! preview

只需让类实现一个接口,然后将接口用于“鸭子类型”...如果类已封装私有字段,这种方式无关紧要,因为您正在作为接口键入。

这来自@Titian Cernicova-Dragomir的答案...

【问题讨论】:

    标签: typescript


    【解决方案1】:

    Private 使类在名义上表现,不可能为具有私有字段的类起别名。另一方面,我们可以使用Pick 删除它们,只获取公共属性:

    let blogPostItem: Pick<BlogPost, keyof BlogPost>;
    
    blogPostItem = {
        hoverTitle: '',
        summary: '',
        title: ''
    }
    

    您也可以使用类型断言来忽略错误。

    【讨论】:

    • 我会说私有属性使 实例类型 表现得名义上;它们本身并没有名义上的行为,因为您甚至无法在课堂之外以有效的方式命名它们。
    • 好的,这样输入blogPostItem 是可行的……但是下面的问题是,如果我不知道我想赋予变量的类类型已经封装了属性怎么办?我是否必须始终使用 Pick 键入或避免封装?
    • 您不应该避免封装,但在您的示例中封装很弱。该类具有私有属性,但可以通过 get/set 访问它们。 ```
    • @jcalz 是的,这就是编译器无法进行结构类型检查的原因......但我无法相信封装与结构类型发生冲突。我只是试图找出如何以及是否有可能封装字段并“输入”该类而不依赖于知道类的构建方式。
    • @meniosmpouras 如果它有私有字段,你会得到一个错误,然后你可以更改为Pick。这是仅编译时私有字段的问题。它们仅由编译器强制执行,并确保没有人在搞乱私有状态,所有消费者都在一定程度上了解私有字段(例如,扩展类不能有同名的字段,你不能增加具有同名字段的类)。当真正的运行时私有字段出现时,它们可能与类型兼容性无关,因为它们在类之外完全不可见
    【解决方案2】:

    修改@Titian Cernicova-Dragomir 的答案,

    Private 使类在名义上表现。

    注意他说的是“名义上的行为”,而不是“名义上的”。

    TypeScript 中 Class 的类型包括私有字段并在结构上比较它们。这是 TS 团队为避免意外访问或覆盖私有字段而做出的设计选择。

    它确实造成了很多困惑和痛点,也是我在 TS 中进行无类编程的主要驱动力之一。

    Pick&lt;&gt; 是绕过这个“限制”的好方法。

    【讨论】:

      猜你喜欢
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多