## 8.结构类型系统
### 8.1 接口的兼容性
* 如果传入的变量和声明的类型不匹配,TS就会进行兼容性检查
* 原理是`Duck-Check`,就是说只要目标类型中声明的属性变量在源类型中都存在就是兼容的
~~~
interface Animal{
name:string;
age:number;
gender:number
}
let a1 = {
name:'zhufeng',
age:10,
gender:0
}
interface Person{
name:string;
age:number
}
////- 要判断目标类型`Person`是否能够兼容输入的源类型`Animal`
function getName(p:Person):string{
return p.name;
}
getName(a1);
//只有在传参的时候两个变量之间才会进行兼容性的比较,赋值的时候并不会比较,会直接报错
let x:Person = {
name:'zhufeng',
age:10,
gender:0
}
~~~
### 8.2 基本类型的兼容性
~~~
//基本数据类型也有兼容性判断
let num : string|number;
let str:string;
num = str;
//只要有toString()方法
let num2 : {
toString():string
}
let str2:string;
num2 = str2;
~~~
### 8.3 类的兼容性
* 在TS中是结构类型系统,只会对比结构而不在意类型
~~~
class Animal{
name:string
}
class Bird extends Animal{
swing:number
}
let a:Animal;
a = new Bird();
let b:Bird;
//并不是父类兼容子类,子类不兼容父类
b = new Animal();
~~~
~~~
class Animal{
name:string
}
//如果父类和子类结构一样,也可以的
class Bird extends Animal{}
let a:Animal;
a = new Bird();
let b:Bird;
b = new Animal();
~~~
~~~
//甚至没有关系的两个类的实例也是可以的
class Animal{
name:string
}
class Bird{
name:string
}
let a:Animal ;
a = new Bird();
let b:Bird;
b = new Animal();
~~~
### 8.4 函数的兼容性
* 比较函数的时候是要先比较函数的参数,再比较函数的返回值
* 参数可以省略
~~~
type sumFunc = (a:number,b:number)=>number;
let sum:sumFunc;
function f1(a:number,b:number){
return a+b;
}
sum = f1;
//可以省略一个参数
function f2(a:number):number{
return a;
}
sum = f2;
//可以省略二个参数
function f3():number{
return 0;
}
sum = f3;
//多一个参数可不行
function f4(a:number,b:number,c:number){
return a+b+c;
}
sum = f4;
~~~
~~~
type GetPerson = ()=>{name:string,age:number};
let getPerson:GetPerson;
//参数一样可以
function g1(){
return {name:'zhufeng',age:10};
}
getPerson = g1;
//多一个属性也可以
function g2(){
return {name:'zhufeng',age:10,gender:'male'};
}
getPerson = g2;
//少一个属性不行
function g3(){
return {name:'zhufeng'};
}
getPerson = g3;
//因为有可能要调用返回值上的方法
getPerson().age.toFixed();
~~~
### 8.5 函数参数的双向协变
* 函数的参数中目标兼容源,或者源兼容目标都可以,只要有一个成立就可以
~~~
type LogFunc = (a:number|string)=>void;
let log:LogFunc;
function log1(a:number){
console.log(a);
}
//在这里定义的参数类型兼容实际的参数类型
log = log1;
function log2(a:number|string|boolean){
console.log(a);
}
//在这里实际的参数类型兼容定义的参数类型
log = log2;
~~~
### 8.6 泛型的兼容性
* 泛型在判断兼容性的时候会先判断具体的类型,然后再进行兼容性判断
~~~
//接口内容为空没用到泛型的时候是可以的
interface Empty<T>{}
let x:Empty<string>;
let y:Empty<number>;
x = y;
//接口内容不为空的时候不可以
interface NotEmpty<T>{
data:T
}
let x1:NotEmpty<string>;
let y1:NotEmpty<number>;
x1 = y1;
interface NotEmptyString{
data:string
}
interface NotEmptyNumber{
data:number
}
let xx3:NotEmptyString;
let yy3:NotEmptyNumber;
xx3 = yy3;
~~~
### 8.7 枚举的兼容性
* 枚举类型与数字类型兼容,并且数字类型与枚举类型兼容
* 不同枚举类型之间是不兼容的
~~~
//数字可以赋给枚举
enum Colors {Red,Yellow}
let c:Colors;
c = Colors.Red;
c = 1;
c = '1';
//枚举值可以赋给数字
let n:number;
n = 1;
n = Colors.Red;
~~~
## 9.类型保护
* 类型保护就是一些表达式,他们在编译的时候就能通过类型信息确保某个作用域内变量的类型
* 类型保护就是能够通过关键字判断出分支中的类型
### 9.1 typeof 类型保护
~~~
function double(input:string|number|boolean){
if(typeof input === 'string'){
return input + input;
}else {
if(typeof input === 'number'){
return input*2;
}else{
return !input;
}
}
}
~~~
### 9.2 instanceof类型保护
~~~
class Animal{
name:string;
}
class Bird extends Animal{
swing:number
}
function getName(animal:Animal){
if(animal instanceof Bird){
console.log(animal.swing);
}else{
console.log(animal.name);
}
}
~~~
### 9.3 null保护
* 如果开启了`strictNullChecks`选项,那么对于可能为null的变量不能调用它上面的方法和属性
~~~
function getFirstLetter(s:string|null){
//第一种方式是加上null判断
if(s == null){
return '';
}
//第二种处理是增加一个或的处理
s = s || '';
return s.charAt(0);
}
//它并不能处理一些复杂的判断,需要加链判断运算符
function getFirstLetter2(s:string|null){
function log(){
console.log(s!.trim());
}
s = s || '';
log();
return s.charAt(0);
}
~~~
### 9.4 链判断运算符
* 链判断运算符是一种先检查属性是否存在,再尝试访问该属性的运算符,其符号为 ?.
* 如果运算符左侧的操作数 ?. 计算为 undefined 或 null,则表达式求值为 undefined 。否则,正常触发目标属性访问,方法或函数调用。
~~~
a?.b; //如果a是null/undefined,那么返回undefined,否则返回a.b的值.
a == null ? undefined : a.b;
a?.[x]; //如果a是null/undefined,那么返回undefined,否则返回a[x]的值
a == null ? undefined : a[x];
a?.b(); // 如果a是null/undefined,那么返回undefined
a == null ? undefined : a.b(); //如果a.b不函数的话抛类型错误异常,否则计算a.b()的结果
a?.(); //如果a是null/undefined,那么返回undefined
a == null ? undefined : a(); //如果A不是函数会抛出类型错误
//否则 调用a这个函数
~~~
### 9.5 可辨识的联合类型
* 就是利用联合类型中的共有字段进行类型保护的一种技巧
* 相同字段的不同取值就是可辨识
~~~
interface WarningButton{
class:'warning',
text1:'修改'
}
interface DangerButton{
class:'danger',
text2:'删除'
}
type Button = WarningButton|DangerButton;
function getButton(button:Button){
if(button.class=='warning'){
console.log(button.text1);
}
if(button.class=='danger'){
console.log(button.text2);
}
}
~~~
### 9.6 in操作符
* in 运算符可以被用于参数类型的判断
~~~
interface Bird {
swing: number;
}
interface Dog {
leg: number;
}
function getNumber(x: Bird | Dog) {
if ("swing" in x) {
return x.swing;
}
return x.leg;
}
~~~
### 9.7 自定义的类型保护
* TypeScript 里的类型保护本质上就是一些表达式,它们会在运行时检查类型信息,以确保在某个作用域里的类型是符合预期的
* 要自定义一个类型保护,只需要简单地为这个类型保护定义一个函数即可,这个函数的返回值是一个类型谓词
* 类型谓词的语法为`parameterName is Type`这种形式,其中`parameterName`必须是当前函数签名里的一个参数名`
~~~
interface Bird {
swing: number;
}
interface Dog {
leg: number;
}
//没有相同字段可以定义一个类型保护函数
function isBird(x:Bird|Dog): x is Bird{
return (<Bird>x).swing == 2;
return (x as Bird).swing == 2;
}
function getAnimal(x: Bird | Dog) {
if (isBird(x)) {
return x.swing;
}
return x.leg;
}
~~~
- 文档简介
- 基础面试题【珠峰2019.8】
- P01_call,aplly区别
- P02_综合面试题讲解2-2
- P03_箭头函数和普通函数区别-综合面试题讲解2-3
- P05_实现indexOf
- P06_综合面试题讲解2-6
- P07_URL解析题
- P08_原型题
- P09_图片延时加载
- P10_正则-包含数字字母下划线
- P11_综合面试题讲解2-11
- P12_英文字母加空格
- P13_数组扁平化并去重
- P14_模拟实现new
- P15_合并数组
- P16_定时器,打印012345
- P17_匿名函数输出值问题
- P18_a在什么情况下打印输出+1+1+1
- P19_对数组的理解
- P20_冒泡排序
- P21_插入排序
- P22_快速排序
- P23_销售额存在对象中
- P24_求数组的交集
- P25_旋转数组
- P26_ [函数柯理化思想]
- P27_ [柯理化函数的递归]
- 网络协议【珠峰2019.6】
- TypeScript+Axios入门+实战【珠峰2019.11】
- 1.数据结构
- 2.函数和继承
- 3.装饰器
- 4.抽象类-接口-泛型
- 05-结构类型系统和类型保护
- 06-类型变换
- AST-抽象语法树
- React性能优化【珠峰2019.10】
- 1-react性能优化
- 2-react性能优化
- 3.react-immutable
- React Hooks【珠峰2019.12】
- 前端框架及项目面试
- 第07章 React 使用
- 7-1 React使用-考点串讲
- 7-2 JSX基本知识点串讲
- 7-3 JSX如何判断条件和渲染列表
- 7-4 React事件为何bind this
- 7-5 React事件和DOM事件的区别
- 7-6 React表单知识点串讲
- 7-7 React父子组件通讯
- 7-8 setState为何使用不可变值
- 7-9 setState是同步还是异步
- 7-10 setState合适会合并state
- 7-11 React组件生命周期
- 7-12 React基本使用-知识点总结和复习
- 7-13 React函数组件和class组件有何区别
- 7-14 什么是React非受控组件
- 7-15 什么场景需要用React Portals
- 7-16 是否用过React Context
- 7-17 React如何异步加载组件
- 7-18 React性能优化-SCU的核心问题在哪里
- 7-19 React性能优化-SCU默认返回什么
- 7-20 React性能优化-SCU一定要配合不可变值
- 7-21 React性能优化-PureComponent和memo
- 7-22 React性能优化-了解immutable.js
- 7-23 什么是React高阶组件
- 7-24 什么是React Render Props
- 7-25 React高级特性考点总结
- 7-26 Redux考点串讲
- 7-27 描述Redux单项数据流
- 7-28 串讲react-redux知识点
- 7-29 Redux action如何处理异步
- 7-30 简述Redux中间件原理
- 7-31 串讲react-router知识点
- 7-32 React使用-考点总结
- 第08章 React 原理
- 8-1 React原理-考点串讲
- 8-2 再次回顾不可变值
- 8-3 vdom和diff是实现React的核心技术
- 8-4 JSX本质是什么
- 8-5 说一下React的合成事件机制
- 8-6 说一下React的batchUpdate机制
- 8-7 简述React事务机制
- 8-8 说一下React组件渲染和更新的过程
- 8-9 React-fiber如何优化性能
- 第09章 React 面试真题演练
- 9-1 React真题演练-1-组件之间如何通讯
- 9-2 React真题演练-2-ajax应该放在哪个生命周期
- 9-3 React真题演练-3-组件公共逻辑如何抽离
- 9-4 React真题演练-4-React常见性能优化方式
- 9-5 React真题演练-5-React和Vue的区别
- 第10章 webpack 和 babel
- 10-1 webpack考点梳理
- 10-2 webpack基本配置串讲(上)
- 10-3 webpack基本配置串讲(下)
- 10-4 webpack如何配置多入口
- 10-5 webpack如何抽离压缩css文件
- 10-6 webpack如何抽离公共代码和第三方代码
- 10-7 webpack如何实现异步加载JS
- 10-8 module chunk bundle 的区别
- 10-9 webpack优化构建速度-知识点串讲
- 10-11 happyPack是什么
- 10-12 webpack如何配置热更新
- 10-13 何时使用DllPlugin
- 10-14 webpack优化构建速度-考点总结和复习
- 10-15 webpack优化产出代码-考点串讲
- 10-16 什么是Tree-Shaking
- 10-17 ES Module 和 Commonjs 的区别
- 10-18 什么是Scope Hostin
- 10-19 babel基本概念串讲
- 10-20 babel-polyfill是什么
- 10-21 babel-polyfill如何按需引入
- 10-22 babel-runtime是什么
- 10-23 webpack考点总结和复习
- 10-24 webpack面试真题-前端代码为何要打包
- 10-25 webpack面试真题-为何Proxy不能被Polyfill
- 10-26 webpack面试真题-常见性能优化方法