8TypeScript中的函数重载、this和as const

51 阅读3分钟

一. 函数的重载(overload)

  • 函数的重载可以理解成同名函数,为的是解决同一函数名接收类型不同的参数,个数不同的参数的问题,js中其实可以通过typeof,arguments来解决这个问题。
  • ts中这里分成以下情况讨论
      1. 参数类型不同
// 直接通过|解决,不需要写两遍函数名称
function print(x: string | number | boolean) {
  console.log(x);
}
    1. 参数的个数不同,这里可以用到重载
function createDate(n: number): Date;

function createDate(year: number, month: number, date: number): Date;

// 这里写函数的实现,需要将上面的所有参数个数的情况都要包含,同名不同参,即为重载
function createDate(a: number, b?: number, c?: number): Date {
  return new Date();
}
// 函数签名
function createDate(n: 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('参数错误,只接收一个或三个参数');
  }
}

createDate(100000000);
createDate(2011, 10, 1);
createDate(2021, 10); // 会报错

三. 指定函数this的类型

  • 总共有四种方法
type Person = { name: string };
function f(this: Person, word: string) {
  console.log(this.name + ' ' + word);
}

// 第一种使用this的方法,强项拼凑出 person.f()
const p: Person & { f: typeof f } = { name: 'frank', f: f };
p.f('hi');

// 第二种使用call,call的第一个参数就是this
f.call(p, 'hi');

// 第三种使用apply,apply和call的唯一区别是参数需要变成数组
f.apply(p, ['hi']);

// 第四种使用bind,绑定this之后需要额外执行,绑定就是提前把this传过去
const f2 = f.bind(p);
f2('hi');
// 本质上就是
f.bind(p)('hi');
// 也可以两次都用bind
const f3 = f.bind(p); // this => p
const f4 = f3.bind(null, 'hi'); // word => 'hi'
f4();

四. ...操作符和展开收集参数

    1. 剩余参数
// array就把所有参数收集起来变成数组
function sum(...array: number[]) {
  return array.reduce((result, n) => result + n, 0);
}

sum(1);
sum(1, 2);
sum(1, 2, 3, 4, 5, 6, 7, 8);
    1. 展开参数
function sum(...array: number[]) {
  // f(array); // 这么写会报错,有两种选择
  // 第一种
  f.apply(null, array);
  // 第二种,也就是把数组的每一项写到括号里
  f(...array);
}

function f(...array: number[]) {
  console.log(array);
}
    1. as const
let a1 = 'b'; // 会推出a1是string类型
const a2 = 'b'; // 会推出a1是'b'类型
let a3 = 'b' as const; // as const就是让变量当作const去推类型,尽量往小的范围推

// 使用场景一,数组
const array1 = [1, 'hi']; // 类型是(string | number) []
const array2 = [1, 'hi'] as const; // 加上as const,类型是readonly [1, "hi"]

// 使用场景二,解决展开的数量对已然报错的问题

function sum(name: number, ...array: number[]) {
  console.log(name, array);
  const a = [1, 2] as const; // number[]
  // readonly [1,2]
  f(...a);
}

function f(a: number, b: number) {
  return a + b;
}
  • 我们可以看到ts中as const的const是真const,可以完全固定住类型,而js中的const如果是array,无法保证数组里面的东西

    1. 参数对象析构
// 对象的析构语法

type Config = {
  url: string;
  method: 'GET' | 'PUT' | 'PATCH' | 'DELETE';
};

function ajax({ url, method }: Config) {
  console.log(url, method);
}
  • 结合之前的其它知识点,默认参数,剩余参数等
type Config = {
  url: string;
  method: 'GET' | 'PUT' | 'PATCH' | 'DELETE';
  data?: unknown;
  headers?: unknown;
};

function ajax(
  { url, method, ...rest }: Config = { method: 'GET', url: '' } as Config
) {
  console.log(url, method);
}

五. 返回值类型是void的情况

// 返回值类型是void的情况
function f1(): void {
  return;
}
function f2(): void {
  return undefined;
}
function f3(): void {}
function f4(): void {
  return null; // 会报错,通过配置"strictNullChecks": false可以通过
}