013 --TypeScript之高级类型

交叉类型可以简单理解为将多个类型合并成一个类型

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

工欲善其事,必先利其器
原文地址:https://www.cnblogs.com/ccbest/p/10945225.html