1 复习对象语法

  • 字面量形式
1
2
3
4
type Person = {
	name: string
	age: number
}
  • 索引签名
1
2
3
4
type Hash = {
	[k: string]: unknown
	length: number
}
  • 映射类型(多用于泛型)
1
2
3
4
type Hash = {
	[k in string]: unknown
    length: number // 报错
}
  • 问号表示可选属性(和undefined不同)

  • readonly只读(类似于const)

2 深入函数语法

2.1 函数类型的声明

  • 对象的语法全部适用于函数
1
2
3
4
5
type F = {
	(a:number, b: number): number	
    // 可以添加这个函数的属性
}
type F = (a: number) => number
  • 声明函数类型的方式(JS)
  1. 普通函数
1
2
3
function f1(a) {}
// ts
function f1(a: number): number {...}
  1. 函数表达式(=后面才算函数表达式)
1
2
3
4
const f2 = function(a) {...}
// ts
const f2 = function(a: number): number {...}
const f2: F2 = function(a) {...}
  1. 箭头函数
1
2
3
const f3 = (a) => {...}
// ts
const f3: F3 = (a) => {...}

2.2 类型谓词

应用于类型判断函数中,函数返回值利用谓词is进行断言,从而作为使得此函数得到TS支持

1
const isRect = (x: Rect | Circle): x is Rect =>  'height' in x

2.2 可选参数+参数默认值

  • addEventListener为例
1
2
3
4
5
6
7
8
9
function addEventListener(
	eventType: string, fn: unknown, useCapture = false	
) {
	// 浏览器实现
    ...
}

// 使用时不传第三个参数
addEventListener('click', () => 1)
  • 类似的还有数组方法(map、forEach)的array属性

1 参数也是函数

  • 直接写
1
2
3
function addEventListener(
	eventType: string, fn: (e: Event) => void, useCapture = false	
) {...}

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

  • 直接写
1
2
3
type Add = (a: number) => (b: number) => number
const add: Add = a => b => a + b
add(1)(2) // 3
  • bind就是柯里化的一个应用,相当于提前把this参数传给函数

2.2 函数重载

  • 两个函数同名,但参数的个数、类型不同,则称两个函数重载

    • 其实js使用if else对参数做判断即可
  • 参数类型不同——联合类型

1
function print(x: string | number) {...}
  • 参数个数不同——重载

  • 以生成Date的两种方式(时间戳和字符串)为例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function createDate(timeStamp: number): Date;
function createDate(year: number, month: number, date: 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('只接受一个或三个参数')
    }
}
  • 其实声明两个函数createDateFromTimeStampcreateDateFromYMD就可以解决函数重载

  • 但如果是面向大众的工具库,建议采用重载的形式,减轻用户在使用过程中的负担

2.3 指定this类型

  1. 想办法拼凑出obj.fn()的调用形式

  2. fn.call() / fn.apply()

  3. fn.bind()()

2.4 扩展运算符...与参数

1 剩余参数

1
2
3
4
function sum(...arr: number[]){
	return arr.reduce((result, number) => result + number, 0)
}
sum(1, 2, 3)

2 展开参数与as const

  • 使用const和let声明变量,其类型推断结果不相同
1
2
3
const a = 'a' // a: 'a'
let a = 'a' // a: string
let a = 'a' as const // a: 'a'
  • ts的const是真const,而js的const是“残废”

  • 因为js的const只是不能重新赋值,但仍然可以修改内部的数据或属性

1
2
3
4
const a = [1, 'hi']
a.push(3) // enable
const a = [1, 'hi'] as const
a.push(3) // disable
  • 在使用展开参数传入数组参数时要注意类型的严格对应
1
2
3
4
5
6
7
function a (a: number, b: number) {
    return a + b
}
const arr = [1, 2]
a(...array) // 因为此时arr的类型推断为number[],不符合函数a的参数类型要求
const arr2 = [1, 2] as const
a(...array) // 编译通过

3 参数对象的析构与默认参数

1
2
3
4
// 剩余参数 + 解构 + 默认参数
function ajax({url, method}: Config = {url: '', method: 'POST'}) {
    console.log(url,method)
}

4 综合应用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
type Config = {
    url: string
    method: 'GET' | 'POST'
    data?: any
    timeout?: number
}
// 剩余参数 + 解构
function ajax({url, method, ...rest}: Config) {
    console.log(url,method)
}
// 剩余参数 + 解构 + 默认参数
// 注意类型声明位置
function ajax2({url, method, ...rest}: Config = {url: '', method: 'POST'}) {
    console.log(url,method)
}
function ajax3({url, method, ...rest} = {url: '', method: 'POST'} as Config) {
    console.log(url,method)
}

2.5 void返回值类型

如果函数返回值类型为void,以下几种情况都是被允许的

1
2
3
4
function f1(): void { return }
function f1(): void { return undefined }
function f1(): void { }
function f1(): void { return null } // no