TypeScript(五)函数

TypeScript 定义函数的四种方式

第一种方式可以直接调用,后三种需要先实现定义的函数再调用。

第一种 函数声明式:

function sum (x: number, y: number): number {
  return x + y
}
// 调用时形参和实参一一对应
sum(1, 2)

第二种 函数表达式:

let sum: (x: number, y: number) => number = (a, b) => a + b
// 或
let sumX = (a: number, b: number): number => a + b
sum(2, 2)
sumX(1, 4)

第三种 接口实现:

interface ISum {
  (x: number, y: number): number;
}
// 跟变量声明是等价的:let ISum: (a: number, b: number) => number
let sum: ISum = (a,b) => a + b
sum(4, 2)

第四种 类型别名:(推荐方式)

type ISum = (x: number, y: number) => number
// 应用如下:
let sum: ISum = (a, b) => a + b
sum(3, 2)

函数类型

函数类型包含两部分:参数类型和返回值类型。

  1. 参数名不一定要相同,只要参数类型匹配,那么就认为它是有效的函数类型。
const sum: (num1: number, num2: number) => number =
  function (x: number, y: number): number { return x + y }
  1. 返回值类型是函数类型的必要部分,如果函数没有返回任何值,必须指定返回值类型为 void 而不能留空。
const sum: (num1: number, num2: number) => void =
  function (x: number, y: number): number { console.log(x + y) }

类型推断

如果在赋值语句的一边指定了类型但另一边没有类型的话,TypeScript编译器会自动识别出类型, 这叫做“按上下文归类”,是类型推论的一种。

const getSum: (x: number, y: number) => number = (x, y) => x + y

可选参数

JavaScript里,每个参数都是可选的。没传参的时候,值就是undefined。但在TypeScript中函数参数默认都是必传的,必传的意思并不是不能传递null和undefined作为实参,而是编译器会检查是否为每个参数传入了值。简而言之,编译器会检查传入实参的个数是否和形参相同。

function bar(name: string, age: number): string {
  return `${name} age is ${age}` 
}

bar('jack', 12) // ok
bar('nike') // Expected 2 arguments, but got 1.
bar('rose', 12, 'shanghai') // Expected 2 arguments, but got 3.

TypeScript的可选参数需要在参数名后使用 ? 标识符 实现可选参数的功能。 比如上例希望 age 是可选的:

function bar(name: string, age?: number): string {
  if (age) return `${name} age is ${age}` 
  return `the name is ${name}` 
}

bar('jack', 12) // ok
bar('nike') // ok
bar('rose', 12, 'shanghai') // Expected 1-2 arguments, but got 3.

注意: 可选参数必须跟在必须参数后面。

参数默认值

可以通过为参数提供一个默认值,当参数是可选的且没有传值或传递的值是undefined时,则会使用参数的默认值。

function fullName(firstName: string, lastName: string = 'Smith') {
  return `${firstName}  ${lastName}` 
}

fullName('Bob') // Bob  Smith
fullName('Bob', undefined) // Bob  Smith
fullName('Bob', 'Adams', 'Sr.')  // Expected 1-2 arguments, but got 3.
fullName("Bob", "Adams")  // Bob  Adams 

参数默认值与可选参数不同之处:

  1. 没有传值时默认参数是取默认值,而可选参数的值是undefined;
  2. 带默认值的参数不需要放在必选参数的后面。如果带默认值的参数出现在必选参数前面,则调用时必须明确的传入 undefined 值来取得默认值。

剩余参数

TypeScript的剩余参数和ES6的剩余参数一样。

function sum(num1: number, ...rest: number[]): number {
  interface ITotal {
    (pre: number, cur: number): number;
  }
  const handle: ITotal = (pre, cur) => pre + cur
  return rest.reduce(handle, num1)
}

sum(1, 2, 3, 4, 5, 6, 7) // 28

this

this与箭头函数

TypeScript在 noImplicitThis 模式下,不允许this上下文隐式定义。

const person = {
  name: 'Mike',
  getName() {
    return function() {
      console.log(this.name)
    }
  }
}
const getName = person.getName()
getName()

上例函数中的this在 noImplicitThis 模式开启时报错(this' implicitly has type 'any' because it does not have a type annotation),未开启时指向window。

可以将返回函数设置成箭头函数解决该问题。

const person = {
  name: 'Mike',
  getName() {
    return () => {
      console.log(this.name)
    }
  }
}
const getName = person.getName()
getName() // 'MIke'

但上面的代码还是会存在一些问题。因为即使能够保证箭头函数里面的 this 与外层函数的this保持一致, 但是外层函数的this不一定就是 dog 这个对象。函数中的this依旧是any类型。

this参数

可以通过给函数添加隐式的 this 参数类型声明。this参数是个假的参数,它出现在参数列表的最前面。

interface IPerson {
  name: string;
  getName(this: IPerson, firstName: string): () => void;
}

const person: IPerson = {
  name: 'Mike',
  getName: function(this: IPerson, firstName: string) {
    return () => {
      console.log( `${this.name} ${firstName}` )
    }
  }
}
const getNameX = person.getName('Mr.')
getNameX()  // Mike Mr.

回调参数里的this

这一部分还没彻底搞清楚,国内几乎找不到深入讲解TypeScript的教程。后续补充。

重载

函数重载允许一个函数通过不同数量或类型的参数,返回不同类型的值。

比如:实现一个函数 reverse,输入数字的时候,输出反转的数字,输入字符串的时候,输出反转的字符串。

通过联合类型实现:

function reverse(val: number | string): number | string {
  if (typeof val === 'number') {
    return Number(val.toString().split('').reverse().join(''))
  } else if (typeof val === 'string') {
    return val.split('').reverse().join('')
  }
}

联合类型的缺陷就是不能精确表达不同输入类型对应的输出类型。这时可以通过函数重载定义多个函数类型。

函数重载实现:

function reverse(num: number): number;
function reverse(str: string): string;
function reverse(val: any): any {
  if (typeof val === 'number') {
    return Number(val.toString().split('').reverse().join(''))
  } else if (typeof val === 'string') {
    return val.split('').reverse().join('')
  }
  return false
}

console.log(reverse(123456))  // 654321
console.log(reverse('sina'))  // 'anis'

以上前两个函数是函数重载列表,第三个是函数实体。

注意:重载只能通过 function 声明。

你可能感兴趣的:(TypeScript(五)函数)