TypeScript——深入函数

172 阅读3分钟

一、 声明函数及其类型

对象的语法全都适用于函数。

// 第一种:先写类型再赋值
type F1 = (a: number, b: number) => number
const f1: F1 = (a, b) => a + b
// 第二种:先实现箭头函数,再获取类型
const f2 = (a: number, b: number): number => {
  return a + b
}
type F2 = typeof f2
// 第三种:先实现普通函数,再获取类型
function f3(this: unknown, a: number, b: number): number {
  return a + b
}
type F3 = typeof f3
// 第四种:先实现匿名普通函数,再获取类型
const f4 = function (this: unknown, a: number, b: number): number {
  return a + b
}
type F4 = typeof f4

二、两种特殊函数

构造函数 与 类型谓词(is)

1. 构造函数

2. 类型谓词(is)

type Person = {
  name: string
}
type Animal = {}
function f1(a: Person | Animal){
  if (isPerson(a)){
    a
  }
}
function isPerson(x: Person | Animal): x is Person { //类型谓词
  return 'name' in x
}

// 箭头函数形式
const isPerson2 = (x: Person | Animal): x is Person => {
  return 'name' in x
}

三、TS 函数语法细节

1. 可选参数

// useCapture 为可选参数
function addEventListener(eventType: string, fn: unknown, useCapture ?: boolean){
  console.log(eventType,fn,useCapture)
}

2. 参数默认值

// useCapture 既可选,又有默认值
// 写法一
function addEventListener(eventType: string, fn: unknown, useCapture = false){
  console.log(eventType,fn,useCapture)
}

// 写法二
function addEventListener(eventType: string, fn: unknown, useCapture ?: boolean){
  if(useCapture === undefined){
    useCapture = false
  }
  console.log(eventType,fn,useCapture)
}

3. 参数也是函数

function addEventListener(
  eventType: string, fn: (e: Event, el: Element) => void, useCapture = false
){
  const element = {} as HTMLElement
  const event = {} as Event
  fn(event,element)
}
addEventListener('click',(e, el) => 1)

4. 返回值也是函数(函数柯里化)

// 平时写的函数
const add = (a: number, b: number) => a + b 
add(6, 18)

// 函数柯里化,返回值是函数
// 写法一
const createAdd = (a: number) => {
  return (b: number) => {
    return a + b
  }
}
// 写法一简写
const createAdd = (a: number) => (b: number) => a + b 
// 写法二:把类型写出来
type CreateAdd = (x: number) => (y: number) => number
const createAdd: CreateAdd = a => b => a + b

createAdd(6)(18)

四、函数重载

同名函数可能参数类型不同,或者参数个数不同,或者都不同。(更推荐使用不同名函数)

// function createDate(n: number): Date
// function createDate(year: number, month: number, day: number): Date
function createDate(a: number, b?: number, c?: number): Date {
  if (a !== undefined && b !== undefined && c !== undefined){
    return new Date(a,b,c)
  }else if (a !== undefined && b === undefined && c === undefined){
    return new Date(a)
  }else{
    throw new Error('只接受一个或三个参数!')
  }
}

createDate(2000000)
createDate(2022, 1, 1)

五、指定 this 类型

image.png

type Person = {
  name: string
}
function f(this: Person, n: number) {
  console.log(n)
}
// 1. person.f(1)
const p: Person & {f: typeof f} = { name: 'Bumble', f: f }
p.f(1)
// 2. f.call(person, 1)
const p2: Person = {name:'Bumble2'}
f.call(p2, 1)
// 3. f.apply(person, [1])
const p3: Person = {name:'Bumble3'}
f.apply(p3, [1])
// 4. f.bind(person)(1)
const p4: Person = {name:'Bumble4'}
const newF = f.bind(p4)
newF(1)

六、... 与参数

1. 剩余参数

剩余参数要放在最后。

function sum(name: string, ...array: number[]){
  return array.reduce((result, n) => result + n, 0)
}
sum('Bumble',1)
sum('Bumble',1,2,3)

2. 展开参数

function sum(name: string, ...array: number[]){
  f.apply(null, array)  //方法一
  f(...array)  //方法二
}
function f(...array: number[]){
  console.log(array)
}

3. as const

把一个值当作常量,类型推断收窄,表示类型不会变。一般用于数组对象或普通对象。

// JS 的 const 还是可以修改数组
const array = [1,'hi']
array = [2, 'hi'] //报错,数组不能被重新赋值
array.push(2) //不报错,虽然使用 const 声明数组,但是可以修改数组
const array = [1,'hi'] as const
array.push(2) //报错
function fn(a: number, b: number){
  return a + b
}
// 如果不加 as const 就无法制约参数个数(因为数组是可修改的)
// 加 as const 之前的类型 number[]
// 加 as const 之后的类型 readonly [1,2]
const a = [1,2] as const 
fn(...a)

4. 参数对象析构

type Config = {
  url: string
  method: 'GET' | 'POST' | 'PATCH' | 'DELETE'
  data ?: unknown
  headers ?: unknown
}
//            //对象析构     //剩余参数           //默认参数
function ajax({url, method, ...rest}: Config = { method: 'GET', url:'' }){
  console.log(url, method)
}

七、void 返回值类型

function f1(): void { //不报错
  return
}
function f2(): void { //不报错
  return undefined
}
function f3(): void { //不报错

} 
function f4(): void { //报错
  return null
}