交叉类型可以简单理解为将多个类型合并成一个类型
function extend<T, U>(first: T, second: U): T & U { let result = {} as T & U for(let id in first) { result[id] = first[id] as any } for(let id in second){ if(!result.hasOwnProperty(id)){ result[id] = second[id] as any } } return result } //为了编译通过,我们让上述的first[id],second[id]断言成了any class Person { constructor(public name: string){ } } interface loggable { log(): void } class ConsoleLogger implements loggable { log(){ } } var jim = extend(new Person('jim'), new ConsoleLogger()) //通过extend函数使两个class扩展到一起,称为交叉类型 jim.name jim.log()
编译后
function extend(first, second) { var result = {}; for (var id in first) { result[id] = first[id]; } for (var id in second) { if (!result.hasOwnProperty(id)) { result[id] = second[id]; } } return result; } //为了编译通过,我们让上述的first[id],second[id]断言成了any var Person = /** @class */ (function () { function Person(name) { this.name = name; } return Person; }()); var ConsoleLogger = /** @class */ (function () { function ConsoleLogger() { } ConsoleLogger.prototype.log = function () { }; return ConsoleLogger; }()); var jim = extend(new Person('jim'), new ConsoleLogger()); //通过extend函数使两个class扩展到一起,称为交叉类型 jim.name; jim.log();
联合类型
function padLeft(value: string, padding: any/*string | number */) { if(typeof padding === 'number'){ return Array(padding + 1).join(' ') + value } if(typeof padding === 'string') { return padding + value } throw new Error(`Expected string or number got ${padding}`) } console.log(padLeft('Hello world', 5))// Hello world console.log(padLeft('Hello world', '123'))//123Hello world //console.log(padLeft('Hello world', true))//这样写也不会报错,因为padding是any //什么是联合类型呢,就是如果给padding做约束,就是padding: string | number
联合类型和交叉类型的区别是什么?联合类型是几种之一,交叉类型是几种类型之和
interface Bird { fly() layEggs() } interface Fish { swim() layEggs() } function getSmallPet(): Fish | Bird { return //... } let pet = getSmallPet() pet.layEggs() //pet.swim()//报错,因为上面声明了是联合类型 //getSmallPet只能是Fish或者Bird //所以只能调用它们共有的方法
类型保护
上述例子中我们如何判断是哪个类型呢
interface Bird { fly() layEggs() } interface Fish { swim() layEggs() } function getSmallPet(): Fish | Bird { return //... } let pet = getSmallPet() if (isFish(pet)){ pet.swim() } else { pet.fly() } //类型谓词的类型保护机制 function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined }
function isNumber(x: any): x is number { return typeof x === 'number' } function isString(x: any): x is string { return typeof x === 'string' } function padLeft(value: string, padding: string | number){ if (isNumber(padding)) { return Array(padding + 1).join('') + value } if (isString(padding)) { return padding + value } throw new Error(`Expected string or number, got ${padding}`) }
typeof的类型保护机制
//typeof对基础类型提供类型保护,可以直接推断出值的类型,而不必像上例那样写 //一般 === 和 !==提供保护 //其他的可以用谓词保护 function padLeft(value: string, padding: string | number){ if (typeof padding === 'number') { return Array(padding + 1).join('') + value } if (typeof padding === 'string') { return padding + value } throw new Error(`Expected string or number, got ${padding}`)
instanceof类型保护
class Bird { fly() { console.log('bird fly') } layEggs(){ console.log('bird lay eggs') } } class Fish { swim(){ console.log('fish swimming') } layEggs(){ console.log('fish lay eggs') } } function getRandomPet(): Fish | Bird { return Math.random() > 0.5 ? new Bird() : new Fish() } let pet = getRandomPet() if (pet instanceof Bird) { pet.fly() } if (pet instanceof Fish) { pet.swim() }
null和undefined
回顾之前的代码
let s = null s = null let sn: string | null = 'bar' sn = null sn = undefined //这段代码在编译时是不会出错的 //加上参数 --strictNullChecks会编译出错
function f(x: number, y?: number){ return x + (y || 0) } f(1,2) f(1) f(1,undefined) //f(1,null)报错 // 'null' is not assignable to parameter of type 'number | undefined'.
在类中也是一样
class C { a:number b?:number//相当于联合类型number | undefined } let c = new C() c.a = 12 c.a = undefined //报错,a为number c.b = 13 c.b = undefined c.b = null //报错
null的类型保护和类型断言
function broken(name: string | null ): string { function postfix(epither: string) { return name!.charAt(0) + '. the' + epither } name = name || 'Bob' return postfix(name) } //上述函数在编译时出错 --strictNullChecks //ts编译器不知道name是否为null //我们可以用类型断言方式给name加上!表示name不为null
高级类型之字符串字面量类型
type Easing = 'ease-in' | 'ease-out' | 'ease-in-out' class UIElement { animate(dx: number, dy: number,easing: Easing) { if (easing === 'ease-in') { //... } else if (easing === 'ease-out') { }else if (easing === 'ease-in-out') { }else { } } } let button = new UIElement() button.animate(0, 0, 'ease-in') //button.animate(0, 0, null)//编译时报错 //Argument of type 'null' is not assignable to parameter of type 'Easing'.
2019-05-30 09:53:16