8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

为什么任意值被认为与空类的类实例兼容?

DevMD 1月前

19 0

我不确定为什么下面的代码片段有效...class GroupLeader { /* snip */};function foo(leader: GroupLeader): void { /* snip: do stuff */}const isLeader = false;const groupLeader =

我不确定为什么下面的代码片段有效......

class GroupLeader { /* snip */ };
function foo(leader: GroupLeader): void { /* snip: do stuff */ }

const isLeader = false;
const groupLeader = isLeader && new GroupLeader();

foo(groupLeader);

在 REPL 中,我可以看到 groupLeader 最终是一个 boolean 类型,但是调用时 TypeScript 编译器(版本 4.4.3)没有生成任何错误 foo(groupLeader) .

为什么这会起作用?

操场

帖子版权声明 1、本帖标题:为什么任意值被认为与空类的类实例兼容?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由DevMD在本站《typescript》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 这是 TypeScript 中的预期行为。

    TypeScript 的类型系统在很大程度上是 结构性的 而不是 名义上的 。因此, 重要的是类型的 or结构 名称 or 声明 ,无论您是否 A 在声明中的任何地方 ,TypeScript 编译器都可以决定类型 B A 子类型 (或“ B 分配 A B ”或“ A 扩展 B 在中具有兼容属性 B 时才重要 A :

    interface A {
        x: string;
        y: number;
    }
    
    interface B {
        x: string;
    }
    
    const a: A = { x: "", y: 0 };
    const b: B = a; // okay, A extends B
    

    最后一行不像名义类型语言那样是一个错误。


    请注意,“明显属性”意味着即使、 和 这样 number , string 基元 boolean 可以被视为在结构上与对象类型兼容,因为当您索引它们时,JavaScript 会自动将一些基元包装在包装器对象中 。因此类型 {length: number} 是 的子类型 string :

    interface L { length: number };
    const l: L = "hello"; // okay
    

    因为 string 值具有 length 类型的明显属性 number .


    在 TypeScript 中, class 声明 通常也按结构处理 (尽管在某些情况下会出现名义上的类型,例如 using instanceof to distinguish between two classes 添加 private 或 protected 成员 add private or protected members )。因此,如果你有一个空类:

    class GroupLeader { }
    

    此类在结构上与空对象类型(没有成员的对象类型)相同 {} 。因此, 任何 可以像对象一样索引的值都将被视为可分配给该类:

    function foo(leader: GroupLeader): void { /* snip: do stuff */ }
    
    foo(true); // okay
    foo(123); // okay
    foo({}); // okay
    foo(() => 3); // okay
    foo(new Date()); // okay
    foo(Symbol("oops")); // okay
    
    foo(null); // error
    foo(undefined); // error
    

    只有 null undefined 不能分配给 GroupLeader ,因为 null 如果像对象一样对它们进行索引, undefined


    这就是发生这种情况的原因。通常,您希望防止此类行为,因此最好避免使用空类和空对象类型,即使在示例代码中也是如此。(有些过时的) TypeScript FAQ 有很多关于此的条目,例如 为什么所有类型都可以分配给空接口? 为什么这些空类的行为很奇怪? 。如果您希望编译器将两种类型视为不同的类型,则应确保它们具有不兼容的形状。

    添加任何 boolean 不共享的 GroupLeader 都会改变事情:

    class GroupLeader { unsnip = 0 };
    
    function foo(leader: GroupLeader): void { /* snip: do stuff */ }
    foo(true); // error
    foo(123); // error
    foo({}); // error
    foo(() => 3); // error
    foo(new Date()); // error
    foo(Symbol("oops")); // error
    
    foo(new GroupLeader()); // okay
    

    当然,仍然存在传递一些结构兼容的内容的可能性:

    foo({ unsnip: 123 }); // okay
    

    如果需要,您可以尝试阻止这种情况( private 属性可以做到这一点),但阻力最小的路径是只编写只关心结构兼容性的代码。无论 的 foo() 实现是什么,它都应该只关心结构 leader 而不是 声明 .

    游乐场链接到代码

返回
作者最近主题: