类型1 & 类型2 & 类型3
interface CatInterface { run(): void } interface DogInterface { jump(): void } // 交叉类型具备全部类型的特性 let pet: CatInterface & DogInterface = { run() {}, jump() {} }
let a: number | string = 2; a = 'hello'; a = undefined; // 能够为其子类型 a = true; // Error: 不能将类型“true”分配给类型“string | number”
// 字符串联合类型 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”
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; }
// 例如: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 函数中设定类型保护区块,会发生什么呢?node
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。webpack
为了让编译器正确的提示错误,有两种可选方法:web
(1)、为 area 方法指定返回值类型typescript
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
三、索引类型spa
使用索引类型,编译器就可以检查使用了动态属性名的代码。例如:从js对象中选取属性的子集,而后创建一个集合code
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 Tblog
对于任何类型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]
interface Person { name: string; gender: string; age: number; } let n: Person['name']; // n 的类型是 string let a: Person['age']; // a 的类型是 number
// 一、用T来约束obj // 二、用K来约束keys数组 // 三、给K增长一个类型约束,让它继承obj的全部属性的联合类型 // 四、函数的返回值是一个数组,数组的元素的类型就是属性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"”
四、映射类型
interface Obj { a: string; b: number; c: boolean; }
4-一、同态
同态的意思是:只会做用于旧类型的属性,而不会引入新的属性
(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-二、非同态,会建立一些新的属性
(1)、Record<key1 | key2 | keyn, T>
接受两个参数:第一个参数是一些预约义的新的属性,第二个参数是一个已知的对象
type RecordObj = Record<'x' | 'y', Obj>;