TypeScript中的private、protected
首先我们要清楚 private
、 protected
现阶段只是javascript
中的保留字(Reserved words
),而非关键字(Keywords
)。因此TypeScript
中的纯类型声明语句,编译后都会被擦除。
class Person {
public name: string;
protected age: number;
private isMarried: boolean;
}
//编译结果
class Person {
}
TypeScript是一个结构类型语言。当比较两个不同的类型时,不管它们来自哪里,如果所有成员的类型都是兼容的,那么就说这些类型本身是兼容的。
interface Named {
name: string;
}
class Bar {
name: string;
}
class Foo {
name: string;
}
// OK, because of structural typing
let a: Named = new Person(); //️
let b: Foo = new Bar(); //️
由于 TypeScript
属性声明默认是 public
,所以上面可以以 b.name
形式访问,而java
则默认是protected
。
但是,当比较具有 private
成员或 protected
成员的类型时,会区别对待这些类型。如果其中一种类型具有private成员,那么另一种类型必须具有来源于同一处声明的private成员。这同样适用于protected成员。
class Bar {
private name: string;
}
class Foo {
private name: string;
}
let bar: Bar = new Foo(); //
//Type 'Foo' is not assignable to type 'Bar'.
//Types have separate declarations of a private property 'name'.
上面的这些概念规则来源于 TypeScript Handbook,这里只是做个简要的引子。
TypeScript
在判断类型兼容时,为什么处理 private
、protected
的规则要有别于 public
, 这究竟有什么潜在的好处。
假设有这样一个场景,目前电动汽车尚且处于发展的初级阶段,汽车品牌特斯拉、蔚来的最大里程数 maxMileage
值一样。
interface Car {
maxMileage: number;
}
class Tesla implements Car {
maxMileage: number = 500;
}
class Nio implements Car {
maxMileage: number = 500;
}
function drive(car :Tesla) {
console.log(car.maxMileage)
}
let tesla = new Tesla();
let nio = new Nio();
drive(tesla); // ️
drive(nio); // ️
由于TypeScript
是结构式语言,因Tesla
、Nio
又有着相同名称、类型的字段 maxMileage
,即使 drive
入参声明为 Tesla
类型,也能通过校验。目前而言,即使误用,drive
的表现一样,不会有问题,但随着技术的发展,两个品牌的 maxMileage
值将不一样,drive
的行为也将千差万别。这个bug将一直潜伏着,直到引起严重故障才会引起关注。
在上例基础上增加1) 2) 两处,多了 private
(protected
亦可) 声明的 brand
属性,来解决结构一样,但又想区分类型的场景,达到类似声明式类型系统的效果。这里就是利用了private
、protected
属性必须源于同一处声明才可判定类型兼容。
class Tesla implements Car {
private brand: string = "Tesla"; // 1)
maxMileage: number = 500;
}
class Nio implements Car {
private brand: string = "Tesla"; //2)
maxMileage: number = 500;
}
function drive(car :Tesla) {
console.log(car.maxMileage)
}
let tesla = new Tesla();
let nio = new Nio();
drive(tesla); // ️
drive(nio); //
//Argument of type 'Nio' is not assignable to parameter of type 'Tesla'.
//Types have separate declarations of a private property 'brand'.
//编译后
class Tesla {
constructor() {
this.brand = "Tesla";
this.maxMileage = 500;
}
}
class Nio {
constructor() {
this.brand = "Tesla";
this.maxMileage = 500;
}
}
虽然达到了我们想要的效果,但类实例会多出 brand
属性,增加了运行时开销,如果这不是你想要的,可以如下处理:
class Tesla implements Car {
//@ts-ignore
private brand: string;
maxMileage: number = 500;
}
class Nio implements Car {
//@ts-ignore
private brand: string ;
maxMileage: number = 500;
}
//编译后
class Tesla {
constructor() {
this.maxMileage = 500;
}
}
class Nio {
constructor() {
this.maxMileage = 500;
}
}
可以看到编译后的代码很纯净了。//@ts-ignore
仅在 strictPropertyInitialization: true
时需要,避免因未初始化属性而编译报错。
Types have separate declarations of a private property
报错还会出现在类extends继承的时候。初看很奇怪,使用姿势不同,但报错信息且类似。
class ElectricVehicle {
private charge() {};
}
//Type 'FF91' is not assignable to type 'ElectricVehicle'.
// Types have separate declarations of a private property 'charge'
class FF91 extends ElectricVehicle { //
private charge() {};
}
通过将 private
改成 protected或public
可以修复。很多文章会提到这是由于 private
语义上是私有的,对子类不可见,所以不能进行覆盖,而protected
、public
语义上就是对子类可见的,子类知道当前在进行覆盖行为,这只是一方面。
我们假设 TypeScript
允许覆盖 private
方法,上面的类声明编译通过。但当我们执行下面语句时,上面的报错再次出现。
let parent = new ElectricVehicle();
let child = new FF91();
parent = child; //
//Type 'FF91' is not assignable to type 'ElectricVehicle'.
// Types have separate declarations of a private property 'charge'
最初的示例,Foo、Bar
只是两个结构类似的类,并无继承关系,判定类型不兼容尚可理解。这里父子类之间类型不兼容就没法自圆了。
所以编译器提前在类声明时就报错,避免延后到使用阶段。这也是为什么 FF91
类声明继承时的报错信息和前面的一样。
TypeScript中的private、protected的更多相关文章
- Java中public,private,protected,和默认的区别
Java中public,private,protected,和默认的区别 1.private修饰词,表示成员是私有的,只有自身可以访问: 2.protected,表示受保护权限,体现在继承,即子类可以 ...
- php class中public,private,protected的区别,以及实例
一,public,private,protected的区别 public:权限是最大的,可以内部调用,实例调用等. protected: 受保护类型,用于本类和继承类调用. private: 私有类型 ...
- PHP中public,private,protected,abstract等关键字用法详解
PHP中常用的关键字 在PHP中包含了很多对函数和类进行限制的关键字,常用的通常有abstract,final,interface,public,protected,private,static等等, ...
- 解析Visual C# 7.2中的private protected访问修饰符
去年12月份,随着Visual Studio 2017 Update 15.5的发布,Visual C#迎来了它的最新版本:7.2. 在这个版本中,有个让人难以理解的新特性,就是private pro ...
- java中public private protected default的区别
1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直 ...
- Java中的private protected public和default的区别
转至:http://blog.sina.com.cn/s/blog_74c571240101jaf5.html 类内部 本包 子类 外部包 public √ √ √ √ pro ...
- php 中 public private protected的区别
public 子类,外部都可调用. protected 子类可以调用,外部不可以调用. private 子类不可以调用,外部不可以调用. <?php class AA { public func ...
- C++中的private/protected/public
访问权限: 继承关系:
- C++中public、protected及private用法
转自:http://www.jb51.net/article/54224.htm 初学C++的朋友经常在类中看到public,protected,private以及它们在继承中表示的一些访问范围,很容 ...
随机推荐
- Python 日志打印之logging.config.dictConfig使用总结
日志打印之logging.config.dictConfig使用总结 By:授客 QQ:1033553122 #实践环境 WIN 10 Python 3.6.5 #函数说明 logging.confi ...
- 浅谈TypeScript,配置文件以及数据类型
TypeScript在javaScript基础上多了一些拓展特性,多出来的是一些类型系统以及对ES6新特性的支持最终会编译成原始的javaScript, 文件名以.ts结尾,编译过后.js结尾,在an ...
- 【Redis3.0.x】实战案例
Redis3.0.x 实战案例 简介 <Redis实战>的学习笔记和总结. 书籍链接 初识 Redis Redis 简介 Redis 是一个速度非常快的键值对存储数据库,它可以存储键和五种 ...
- Flutter 布局类组件:弹性布局(Flex)
前言 弹性布局允许子组件按照一定比例来分配父容器空间,Flutter中的弹性布局主要通过Flex和Expanded来配合实现. Flex Flex组件可以沿着水平或垂直方向排列子组件,如果你知道主轴方 ...
- 9. 细节见真章,Formatter注册中心的设计很讨巧
目录 本文提纲 版本约定 你好,我是A哥(YourBatman). Spring设计了org.springframework.format.Formatter格式化器接口抽象,对格式化器进行了大一统, ...
- PMP知识领域
· 十大知识领域 整合-项目整合管理 识别.定义.组合.统一和协调个项目管理过程组的各种过程和活动而展开的活动与过程. 整合:统一.合并.沟通和简历联系:贯穿项目始终 七个过程组 一.制定项目章程(启 ...
- Linux Bash Shell常用快捷键
Linux Bash Shell常用快捷键 table { margin: auto } 快捷键 功能 tab 补全 ctrl + a 光标回到命令行首 ctrl + e 光标回到命令行尾 ctrl ...
- zabbix客户端安装配置
1.下载,解压并安装zabbixtar zxvf zabbix-2.0.12.tar.gzcd zabbix-2.0.12./configure --prefix=/usr/local/zabbix ...
- iostat的输出
第一行显示的时子系统启动以来的平均值,接下来的报告显示了增量的平均值,每个设备一行 Device: rrqm/s wrqm/s r/s w/s rsec/s ...
- ctfhub技能树—web前置技能—http协议—响应包源代码
打开靶机环境 查看网页是一个贪吃蛇小游戏 根据提示查看源码 发现flag 至此HTTP协议结束