深入函数

79 阅读3分钟

一、深入对象语法

  • 普通声明
// 方式一
type Person = {
  name: string
}
interface Person {
  name: string
}
// 方式二:索引签名 Index Signature
type Hash = {
  [k: string]: unknown,
  length: number
}
type List = {
  [k: string]: unknown,
  length: number
}
// 方式三:映射类型 Mapped Type,映射类型不能声明属性和方法,多用于泛型
type Hash = {
  [k in string]: unknown
}
  • 可选 key 声明
interface InputProps {
  defaultvalue?: string,
  value?: boolean,
  onChange?: () => void
}
  • readonly(只读)使用
interface User {
  readonly id: number,
  readonly name: number,
  readonly scores: number[],
  age?: number
}

二、深入函数语法,声明对象的语法都可以声明函数

  • js 中声明函数的三种方式
// 方式一:普通函数
function f1(a) {
  return a + 1
}
// 方式二:函数表达式
const f2 = function (a) {
  return a + 1
}
// 方式三:箭头函数
const f3 = (a) => {
  return a + 1
}
  • ts 中声明函数的方式
// 普通函数
function f1(a: number): number {
  return a + 1
}
// 函数表达式
// 1 在左边声明类型(推荐)
type F2 = (a: number) => number
const f2: F2 = function (a) {
  return a + 1
}
// 2 在右边声明类型
const f3 = function (a: number): number {
    return a + 1
}
// 箭头函数
// 1. 在左边声明类型(推荐)
type F4 = (a: number) => number
const f4: F4 = (a) => {
  return a +1
}
// 2. 在右边声明类型
const f5 = (a: number): number => {
    return a + 1
}

三、两种特殊的函数

  • 构造函数(先不写)
  • 类型谓词 is--用处:判断参数类型
// 判断参数类型
// 1 普通参数
type F1 = (s: string | string[]) => void 
const f1: F1 = (s) => {
  if (s instanceof Array) {
    s.slice(0, 1)
  } else {
    s.split('')
  }
}
// 2 非 js 类型的参数
type Person = {
  name: string
}
type Animal = {}
type F2 = (p: Person | Animal) => void

// 这里使用普通函数来声明,不要使用箭头函数(箭头函数可能会有问题 )
function isPerson(p: Person | Animal): p is Person {
  return 'name' in p
}
const f2: F2 = function (p) {
  if (isPerson(p)) {
    p // Person
  } else {
    p // Animal
  }
}

四、函数柯里化

// const createAdd = (a: number) => {
//   return (b: number) => {
//     return a + b
//   }
// }
// 等价于
const createAdd = (a: number) => (b: number) => a + b
// 声明类型
type CreateAdd = (a: number) => (b: number) => number
const createAdd2: CreateAdd = a => b => a + b

五、函数重载

含义:当参数类型不同 | 函数参数个数不同 | 都不同 的同名函数就叫函数重载

// 前面声明同名,最后写函数体
function getDate(t: number): Date
function getDate(y: number, m:number, d:number): Date
function getDate(a: number, b?: number, c?:number): Date {
  if (a !== undefined && b === undefined && c === undefined) {
    return new Date(a)
  } else if (a !== undefined && b !== undefined && c !== undefined) {
    return new Date(a, b, c)
  } else {
    throw new Error('参数非法')
  }
}
getDate(10000000)
getDate(1996, 10, 7)

六、指定 this 的类型

四种方式:构造对象、call、apply、bind

type Person = {
  name: string
}
function f(this: Person, word: string): void { 
  console.log(this.name + ' ' + word)
}

// 方式一:构造对象
const p1: Person & { f: typeof f } = {
  name: 'rourou1', f
}
// 不可以直接将 p 传进去,会报应有 1 个参数,但获得 2 个的错误
// f(p, 'sayHi')
p1.f('sayHi')

// 方式二:f.call()
const p2: Person = {
  name: 'rourou2'
}
f.call(p2, 'sayHi')

// 方式三:f.apply()
const p3: Person = {
  name: 'rourou3'
}
f.apply(p3, ['sayHi'])

// 方式四:f.bind()
const p4: Person = {
  name: 'rourou4'
}
f.bind(p4)('saiHi')

七、剩余参数,必须是函数的最后一个参数

function sum(...array: number[]): number {
  return array.reduce((p, c) => p + c, 0)
}
sum(1, 2, 3)
sum(1, 1, 1, 1, 1)

八、展开参数

function f(...array: number[]): void {
  console.log(array)
}
// 剩余参数
function sum(...array: number[]): number {
  // 展开参数
  f(...array)
  return array.reduce((p, c) => p + c, 0)
}

九、as const

含义:将变量变为常量,通常用于数组/对象中(因为在js中,一个数组就算是const,也可以通过push方法改变数组)

function sum(a: number, b: number): number {
  return a + b
}
// const arr = [1, 2] 并不是严格意义上的常量
const arr = [1, 2] as const // 即 arr 为 readonly
sum(...arr)

十、大融合

type Config = {
  url: string,
  method: 'GET' | 'POST' | 'PATCH' | 'DELETE',
  data?: unknown,
  headers?: unknown
}
// 参数解构&设置默认值
// 方式一:类型在 = 左边声明
function ajax1({ url, method, ...rest }: Config = { method: 'GET', url: '' }): void {
  console.log(url, method, data, headers)
}
// 方式二:类型在 = 右边声明(即断言)
function ajax2({ url, method, ...rest } = { method: 'GET', url: '' } as Config): void {
  console.log(url, method, data, headers)
}