TypeScript基础之类的类型兼容性

前言

文中内容都是参考https://www.typescriptlang.org/docs/handbook/type-compatibility.html#handbook-content 内容。

类的类型兼容性

类与对象字面量和接口差不多,但有一点不同:类有静态部分和实例部分的类型。
在比较两个类型是否兼容时,除了遵照结构类型兼容规则(如果x要兼容y,那么y至少具有与x相同的属性。), 还需要注意以下几点:

  • 只需比较类实例的属性和方法是否兼容即可;
  • 静态成员和构造函数不会比较;
  • 私有(private)、受保护(protected)的属性和方法,必须来自相同的类

举例进行分析:

class Animal {
  feet: number;
  constructor(name: string, numFeet: number) { }
}

class Size {
  feet: number;
  constructor(numFeet: number) { }
}

let a: Animal;
let s: Size;

a = s;  // 没毛病
s = a;  // 没毛病

以上代码中, 类Animal与类Size拥有共同的属性feet, 即使它们的构造函数不同, 这两个类也是互相兼容。

类的私有成员和受保护成员

类的私有成员和受保护成员会影响兼容性。 当检查类实例的兼容时,如果目标类型包含一个私有成员,那么源类型必须包含来自同一个类的这个私有成员。 同样地,这条规则也适用于包含受保护成员实例的类型检查。 这允许子类赋值给父类,但是不能赋值给其它有同样类型的类。
举例说明:

class Animal {
  private feet: number;
  constructor(name: string, numFeet: number) { }
} 

class Size {
  private feet: number;
  constructor(numFeet: number) { }
}

let a: Animal;
let s: Size;

a = s; 
// 不能将类型“Size”分配给类型“Animal”。
// 类型具有私有属性“feet”的单独声明

当把 Size赋值给 Animal的时候,得到一个错误,说它们的类型不兼容。 尽管 Size里也有一个私有成员 feet,但它明显不是 Animal里面定义的那个。
对于protected成员也一样:

class Animal {
  protected feet: number;
  constructor(name: string, numFeet: number) { }
} 

class Size {
  feet: number;
  constructor(numFeet: number) { }
}

let a: Animal;
let s: Size;

a = s;  
// 不能将类型“Size”分配给类型“Animal”。
// 属性“feet”受保护,但类型“Size”并不是从“Animal”派生的类

因为类 Animal 中的成员 feet 是受保护的,所以不能赋值成功。

举例: 目标类型包含一个私有成员,源类型也包含来自同一个类的这个私有成员

class Animal {
  private name: string;
  constructor(theName: string ) { this.name = theName; }
}

class Dog extends Animal {
  constructor() { super("Dog"); }
}

let a: Animal = new Animal('Bird');
let d: Dog = new Dog();

a = d; // 没毛病  
d = a; // 没毛病 父类之所以能够给赋值给子类,是因为子类中没有成员 

这个例子中有 AnimalDog两个类, DogAnimal类的子类。 我们创建了几个这些类的实例,并相互赋值来看看会发生什么。
因为 AnimalDog 共享了来自Animal里的私有成员定义 private name: string,因此它们是兼容的。
前提也是需要符合成员的类型都是兼容的, 如果子类中有其他非静态属性或方法, 则父类赋值给子类会报错。

class Animal {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}

class Dog extends Animal {
  age: number;
  constructor(age: number) {
    super("Dog");
    this.age = age;
  }
}

let a: Animal = new Animal("Bird");
let d: Dog = new Dog(2);

a = d; // 没毛病
d = a; // Property 'age' is missing in type 'Animal' but required in type 'Dog'.

举例说明: 静态成员不会比较

class Animal {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}

class Dog extends Animal {
  static age: number = 1;
  constructor() {
    super("Dog");
  }
  static run() {}
}

let a: Animal = new Animal("Bird");
let d: Dog = new Dog();

a = d; // 没毛病
d = a; // 没毛病

Dog类中有静态属性age和静态方法run, 但是比较两个类型是否兼容时, 静态成员和构造函数不会比较, 所以父子类型相互兼容。

以上ts代码均在 https://www.typescriptlang.org/play 上运行过,版本为4.7.2。
最后, 如有错误,欢迎各位大佬指点!感谢!

参考资料

https://www.typescriptlang.org/docs/handbook/type-compatibility.html#handbook-content

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值