1、交叉类型
 
将多个类型合并成一个类型,新的类型将具有所有类型的特性,适用于对象混用
 
语法:
类型1 & 类型2 & 类型3
interface CatInterface {
run(): void
} interface DogInterface {
jump(): void
} // 交叉类型具有所有类型的特性
let pet: CatInterface & DogInterface = {
run() {},
jump() {}
}
2、联合类型
 
声明的类型并不确定,可以为多个类型中的一个。用竖线(|)分隔每个类型,所以number | string | boolean表示一个值可以是number,string,或boolean
let a: number | string = 2;
a = 'hello';
a = undefined; // 可以为其子类型 a = true; // Error: 不能将类型“true”分配给类型“string | number”
(1)、字面量联合类型:不仅限制类型,还限制取值
// 字符串联合类型
let x: 'typescript' | 'webpack' | 'nodejs'; x = 'webpack';
x = 'hello'; // Error: 不能将类型“"hello"”分配给类型“"typescript" | "webpack" | "nodejs"” // 数字联合类型
let y: 1 | 2 | 3; y = 3;
y = 33; // Error: 不能将类型“33”分配给类型“1 | 2 | 3” let z: 'typescript' | 2; z = 'typescript';
z = 2;
z = 1; // Error: 不能将类型“1”分配给类型“"typescript" | 2”
(2)、对象联合类型:在类型未确定的情况下,只能访问所有类型的公用成员
enum Pet { Dog, Cat };

interface DogInterface {
run(): void;
eat(): void;
} interface CatInterface {
jump(): void;
eat(): void;
} class Dog implements DogInterface {
run() {};
eat() {};
} class Cat implements CatInterface {
jump() {};
eat() {};
} function getPet(pet: Pet) {
// let smallPet: Dog | Cat
let smallPet = pet === Pet.Dog ? new Dog() : new Cat(); // 类型不确定时,只能取公有成员
smallPet.eat(); smallPet.run(); // 类型“Dog | Cat”上不存在属性“run”
smallPet.jump(); // 类型“Dog | Cat”上不存在属性“jump” return smallPet;
}
(3)、可区分的联合类型:这种模式从本质上来讲是结合了联合类型和字面量联合类型的一种类型保护方法
 
其核心思想是:如果一个类型是多个类型的联合类型,并且每个类型之间有一个公共的属性,那么就可以利用这个公共的属性创建不同的类型保护区块
// 例如:Shape是多个类型的联合类型,每个类型都具有一个公共属性kind,由此在 switch中建立了不同类型的保护区块

interface Rectangle {
kind: 'rectangle';
width: number;
height: number;
} interface Square {
kind: 'square';
size: number;
} type Shape = Rectangle | Square; function area(s: Shape) {
switch(s.kind) {
case 'rectangle':
return s.width * s.height;
case 'square':
return s.size * s.size;
}
}

如果又添加了一个联合类型,但是又没有在 area 函数中设定类型保护区块,会发生什么呢?

interface Rectangle {
kind: 'rectangle';
width: number;
height: number;
} interface Square {
kind: 'square';
size: number;
} // 添加新的联合类型
interface Circle {
kind: 'circle';
r: number;
} type Shape = Rectangle | Square | Circle; function area(s: Shape) {
switch(s.kind) {
case 'rectangle':
return s.width * s.height;
case 'square':
return s.size * s.size;
}
} console.log(area({ kind: 'circle', r: 1 })); // undefined

执行程序打印出了一个结果 undefined,由于上例中并没有在 area 方法中为 Circle 指定计算面积的方法,理论上应该提示错误,而不是直接返回 undefined。

为了让编译器正确的提示错误,有两种可选方法:

(1)、为 area 方法指定返回值类型

function area(s: Shape): number {
switch(s.kind) {
case 'rectangle':
return s.width * s.height;
case 'square':
return s.size * s.size;
}
}

(2)、利用never类型

// 给定一个 default 分支,通过判断 s 是不是 never 类型来提示错误。
// 如果是 never 类型,则可以在前面的分支中找到对应的执行代码;
// 如果不是 never 类型,则说明前面的代码有遗漏,需要补全 function area(s: Shape): number {
switch(s.kind) {
case 'rectangle':
return s.width * s.height;
case 'square':
return s.size * s.size;
default:
return ((e: never) => { throw new Error(e) })(s);
// 类型“Circle”的参数不能赋给类型“never”的参数
}
}

通过错误提示补全代码

function area(s: Shape): number {
switch(s.kind) {
case 'rectangle':
return s.width * s.height;
case 'square':
return s.size * s.size;
case 'circle':
return Math.PI * s.r ** 2
default:
return ((e: never) => { throw new Error(e) })(s);
}
} console.log(area({ kind: 'circle', r: 1 })); // 3.141592653589793

3、索引类型

使用索引类型,编译器就能够检查使用了动态属性名的代码。例如:从js对象中选取属性的子集,然后建立一个集合

let obj = {
a: 1,
b: 2,
c: 3
} function getValues(obj: any, keys: string[]) {
return keys.map(key => obj[key])
} // obj 中存在的属性
console.log(getValues(obj, ['a', 'b'])); // [ 1, 2 ] // obj 中不存的属性,返回 undefined,而没有提示报错
console.log(getValues(obj, ['e', 'f'])); // [ undefined, undefined ]

索引类型可以用来解决上例中的问题,在认识索引类型之前需要先了解几个概念:

(1)、索引类型查询操作符   keyof T

对于任何类型T,keyof T 的结果是 类型T的所有公共属性的字面量的联合类型

interface Person {
name: string;
gender: string;
age: number;
} let personProps: keyof Person; // 'name' | 'gender' | 'age'
console.log(personProps)

(2)、索引访问操作符     T[K]

类型T的属性K所代表的类型
interface Person {
name: string;
gender: string;
age: number;
} let n: Person['name']; // n 的类型是 string
let a: Person['age']; // a 的类型是 number
(3)、泛型约束      T extends U
表示泛型变量可以继承某个类型获得某些属性
 
结合以上三点来改造 getValues 函数
// 1、用T来约束obj
// 2、用K来约束keys数组
// 3、给K增加一个类型约束,让它继承obj的所有属性的联合类型
// 4、函数的返回值是一个数组,数组的元素的类型就是属性K对应的类型 let obj = {
a: 1,
b: 2,
c: 3
} function getValues<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
return keys.map(key => obj[key])
} // obj 中存在的属性
console.log(getValues(obj, ['a', 'b'])); // [ 1, 2 ] console.log(getValues(obj, ['e', 'f']));
// Error:不能将类型“string”分配给类型“"a" | "b" | "c"”

4、映射类型

通过映射类型,可以从一个旧的类型生成一个新的类型,比如把一个类型中的所有属性变成只读
 
interface Obj {
a: string;
b: number;
c: boolean;
}

4-1、同态

同态的意思是:只会作用于旧类型的属性,而不会引入新的属性

(1)、Readonly<T>   将旧类型中的每一个成员都变成只读

type ReadonlyObj = Readonly<Obj>;

(2)、Partial<T>   把旧类型中的每一个成员都变成可选的

type PartialObj = Partial<Obj>;

(3)、Pick<T, key1 | key2 | keyn>   可以抽取旧类型中的一些子集

接受两个参数:第一个是要抽取的对象,第二个是要抽取的属性的key

type PickObj = Pick<Obj, 'a' | 'c'>;

4-2、非同态,会创建一些新的属性

(1)、Record<key1 | key2 | keyn, T>

接受两个参数:第一个参数是一些预定义的新的属性,第二个参数是一个已知的对象

type RecordObj = Record<'x' | 'y', Obj>;

映射类型的本质是一些预定义的泛型接口,通常还会结合索引类型来获取对象的属性和属性值,从而将一个对象映射成想要的结构

Typescript 实战 --- (8)高级类型的更多相关文章

  1. TypeScript完全解读(26课时)_12.TypeScript完全解读-高级类型(1)

    12.TypeScript完全解读-高级类型(1) 高级类型中文网的地址:https://typescript.bootcss.com/advanced-types.html 创建新的测试文件 ind ...

  2. TypeScript完全解读(26课时)_13.TypeScript完全解读-高级类型(2)

    13.TypeScript完全解读-高级类型(2) 高级类型中文网的地址:https://typescript.bootcss.com/advanced-types.html 创建文件并在index. ...

  3. 为vue3.0学点typescript, 解读高级类型

    知识点摘要 本节课主要关键词为: 自动类型推断 / 类型断言 / 类型别名(type) / 映射类型(Pick/Record等...) / 条件类型(extends) / 类型推断(infer) 自动 ...

  4. C# vs TypeScript - 高级类型

    总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ...

  5. TypeScript入门-高级类型

    高级类型 交叉类型 交叉类型,就是将多个类型合并为一个新的类型,这个新的类型具有这多个类型的成员,含有这几个类型的所有特性,是他们的综合体,像是集合的并集 例子: function extend< ...

  6. 从C#到TypeScript - 高级类型

    C# vs TypeScript - 高级类型 上一篇讲了基础类型,基本上用基础类型足够开发了,不过如果要更高效的开发,还是要看下高级类型,这篇和C#共同点并不多,只是延用这个主题. 联合类型 可以从 ...

  7. Typescript高级类型与泛型难点详解

    最近做的TS分享,到了高级类型这一块.通过琢磨和实验还是挖掘出了一些深层的东西,在此处做一下记录,也分享给各位热爱前端的小伙伴.   其实在学习TS之前就要明确以下几点:   1. typescrip ...

  8. typescript枚举,类型推论,类型兼容性,高级类型,Symbols(学习笔记非干货)

    枚举部分 Enumeration part 使用枚举我们可以定义一些有名字的数字常量. 枚举通过 enum关键字来定义. Using enumerations, we can define some ...

  9. TypeScript 之 基础类型、高级类型

    基础类型:https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/Basic%20Types.html 高级类型:https ...

  10. typescript进阶篇之高级类型与条件类型(Readonly, Partial, Pick, Record)

    本文所有东西尽可在 typescript 官网文档寻找,但是深浅不一 高级类型 lib 库中的五个高级类型 以下所有例子皆以 person 为例 interface Person { name: st ...

随机推荐

  1. MongoDB_05_更新和删除

    文档的更新和删除 更新文档的方法: db.collection.update(query,update,options) //或 db.collection.update( <query> ...

  2. pikachu平台搭建

    1.将pikachu转移至htdocs 2.然后打开pikachu文件夹里的inc文件夹 3.里面对应的内容该成之前刚刚设置好的数据库服务器地址,用户名,密码和端口号 4.打开浏览器,输入http:/ ...

  3. 【visio】数据可视化 - 链接到外部数据

    编辑数据的时候,纯粹一个一个地手动输入,效率过低,visio提供了连接外部数据的功能,以加快数据导入,该功能也同时能够针对外部数据的改变,更新visio内部数据. 1. 创建外部源数据 visio支持 ...

  4. honoka和格点三角形(牛客寒假训练营day1)

    可以把面积为1的好三角形分成两类分开统计:两条边和两个坐标轴平行:只有一条边和某个坐标轴平行. 对于第一种情况,一定是1*2或者2*1的形式,一个1*2的矩形中含有4个不同的三角形.总数是4*((n- ...

  5. Atcoder Beginner Contest151E(排列组合)

    排列组合 #define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h> using namespace std; ]; ; ]; long lo ...

  6. django view 视图控制之数据返回的视图函数

    八.视图 view 概述:views.py定义的python函数,它接受Web请求并且返回Web响应. 有几个页面就有几个视图view user出入url地址,发送request--->urls ...

  7. Django Web接口开发

    什么是接口 接口一般来讲分为两种: (1)程序内部的接口:方法与方法.模块与模块之间的交互,程序内部抛出的接口,如登录发帖,发帖就必须要登录,如果不登录不能发帖,发帖和登录这两个模块之间就要有交互,就 ...

  8. Javascript自增、自减运算符

    JavaScript自增.自减运算符与表达式语法 var i++; var-- 声明变量 i-- 变量名 ++ -- 自增运算符 JavaScript自增.自减运算符与表达式 JavaScript自增 ...

  9. MAC记住 git的用户名密码

    问题:第一次使用MAC的git垃取代码时,连续输错密码.以为垃取不下来,就让同事用它的git账号和密码垃取了一次拉去成功了.之后我再配置git的用户名和密码设置称自己的.往后每次拉去和提交都显示同事的 ...

  10. 《实战Java高并发程序设计》读书笔记四

    第四章 锁的优化及注意事项 1.锁性能的几点建议 减小锁持有时间: 系统持有锁时间越长锁竞争程度就越激烈,只对需要同步的方法加锁,可以减小锁持有时间进而提高锁性能. 减少锁的持有时间有助于降低锁冲突的 ...