learn-typescript

函数

函数类型

为函数定义类型

// 命名函数
function add(x: number, y: number): number {
  return x + y
}

// 匿名函数
let add = function (x: number, y: number): number {
  return x + y
}

完整的函数类型

let add: (baseValue: number, increment: number) => number = 
  function (x: number, y: number): number {
    return x + y
  }

自动类型推断

如果在赋值语句的一边指定了类型而另一边没有,TypeScript 编译器会自动识别类型:

let myAdd = function (x: number, y: number): number {
  return x + y
}

let myAdd: (x: number, y: number) => number = 
  function (x, y) {
    return x + y
  }

可选参数和默认参数

JavaScript 中参数可传可不传,如果没传,会默认为 undefined
但是 TypeScript 中必须传入的参数个数与函数期望的个数一致。

function buildName(firstName: string, lastName: string): string {
  return firstName + ' ' + lastName
}

剩余参数

JavaScript 中可以通过 arguments 来访问所有传入的参数,
而在 TypeScript 中可以通过 剩余参数(...rest) 来获取传入的所有多余的参数组成的数组。

function printNumber(num: number, ...restNumbers: number[]): void {
  console.log(num)
  console.log(`restNumbers: `, restNumbers)
}

printNumber(1)

// 1
// restNumbers:

printNumber(1,2,3)

// 1
// restNumbers: 2,3

剩余参数是一个数组,会被当作个数不限的可选参数,可以一个都没有,此时为空数组。

带有剩余参数的函数定义:

let printNumberFun: (num: number, ...restNumbers: number[]): void = printNumber

This

箭头函数 => 不是普通的 function, 没有独立的作用域,所以箭头函数中的 this 是该箭头函数定义时所属的最近的一个作用域。

// case one: `this` 的指向在调用时才能确定
window.name = 'window'
let obj = {
  name: 'yuusha',
  printName: function() {
    console.log(this.name)
  }
}

obj.printName()  // 'yuusha'

let foo = obj.printName
foo()  // 'window'

// case two: 箭头函数中的this始终指向该箭头函数被创建时所在的作用域 【相当于普通函数使用bind(this)的效果】
let obj = {
  name: 'yuusha',
  printName: function () {
    return () => {
      console.log(this.name)
    }
    // 相当于:
    /* return function(){
      console.log(this.name)
    }.bind(this) */
  }
}

let foo = obj.printName()
foo()  // 'yuusha'
let foo2 = obj.printName.call({name: 'tempName'})
foo2() // 'tempName'

this参数

TypeScript 支持给方法显式地提供一个 this 参数,放在参数列表最前面,限制该方法中的 this 的类型,从而避免一些错误:

interface UseThisDemo {
  name: string
  age: number
  printInfo(this: UseThisDemo): void
}

let person: UseThisDemo = {
  name: 'yuusha',
  age: 24,
  printInfo: function (this: UseThisDemo){
    console.log(this.name, this.age)
  }
}

person.printInfo()
// let foo = person.printInfo
// foo()  // Error, `this` is not `UseThisDemo` type
let foo = person.printInfo.bind({name: 'xyz', age: 123, printInfo(){}})
foo()  // OK, `this` refers to a `UseThisDemo` object

函数重载

TypeScript 中允许为同一个函数提供多个函数类型定义来进行 函数重载

// 根据传入参数的不同调用不同的处理函数
function getBirthYear(age: number): number
function getBirthYear(date: Date): number

function getBirthYear(x: number | Date): number {
  if (typeof x === 'number') {
    return new Date().getFullYear() - x
  } else {
    return x.getFullYear()
  }
}

console.log(getBirthYear(24)) // 2019 - 24 = 1995
console.log(getBirthYear(new Date('1995-10-26'))) // 1995

注意:

  1. function getBirthYear(x: number | Date) 不是重载的一部分,上面的代码只有两个重载: 一个接收数字,一个接收日期。
  2. 定义重载时,最好将最精确的定义放在最前面,因为 TypeScript 编译器从前往后进行重载匹配。