TypeScript 中的函数类型

1,175 阅读3分钟

函数类型签名

函数类型签名是 TypeScript 中描述函数入参类型与返回值类型的一种方式。它使用 : 语法进行类型标注,这样能够清晰地知道每个函数期望接收什么类型的参数,以及它将返回什么类型的值。例如:

function func(name: string): number {
  return name.length;
}

函数的声明与表达式

在 JavaScript 中,可以通过函数声明或函数表达式来定义函数。TypeScript 通过类型注解增强了这些定义,能够更准确地指定函数的类型。例如:

// 函数声明
function func(name: string, age: number): string {
  return `Hello, ${name}! You are ${age} years old.`;
}
// 函数表达式
const func = function(name: string, age: number): string {
  return `Hello, ${name}! You are ${age} years old.`;
}

箭头函数

箭头函数是 ES6 的一个特性,在 TypeScript 中,箭头函数的类型签名与普通函数类似,但语法更简洁。

// 箭头函数的类型注解
const func = (name: string, age: number): string => {
  return `Hello, ${name}! You are ${age} years old.`;
};

const message = func("lin", 18);

可以使用类型别名来为函数创建更复杂的类型注解:

type TestFunction = (name: string, age: number) => string;

const func: TestFunction = (name, age) => {
  return `Hello, ${name}! You are ${age} years old.`;
};

可以使用接口来定义函数类型:

interface TestInterface {
  (name: string, age: number): string;
}

const func: TestInterface = (name, age) => {
  return `Hello, ${name}! You are ${age} years old.`;
};

void 类型

在 TypeScript 中,没有返回值的函数应该被标记为 void 类型。这与 JavaScript 中的 undefined 不同,它更明确表明函数不返回任何有意义的值:

// 没有返回值的函数
function func(): void { }

可选参数与 rest 参数

// 可选参数
function func1(name: string, age?: number): number {
  const inputAge = age || 18;
  return name.length + inputAge;
}

// rest 参数
function func(arg1: string, ...rest: number[]): number {
  return arg1.length + rest.reduce((a, b) => a + b, 0);
}

函数重载

函数重载能够为同一个函数名定义多个类型签名,每个签名可以有不同的参数类型和返回值类型。能够根据传入的参数类型来决定函数的行为:

function func(foo: number, bar: true): string;
function func(foo: number, bar?: false): number;
function func(foo: number, bar?: boolean): string | number {
  if (bar) {
    return String(foo);
  } else {
    return foo * 666;
  }
}

异步函数与 Generator 函数

异步函数和 Generator 函数在 TypeScript 中也有特定的类型签名。能够在处理异步操作和迭代器时保持代码的类型安全:

// 异步函数
async function asyncFunc(): Promise<void> {}

// Generator 函数
function* genFunc(): Iterable<void> {}

示例1

在函数类型中处理错误,并且使用 try-catch 结构与异步函数结合的例子。

async function fetchData(url: string): Promise<Data> {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    throw error; // or handle the error appropriately
  }
}

示例2

创建一个API请求函数,该函数可以处理不同类型的请求和响应。

首先,定义一些类型来描述请求配置和响应:

// 定义一个类型来描述API请求配置
interface ApiRequestConfig {
  url: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  headers?: Record<string, string>;
  body?: object;
}

// 定义一个泛型接口来描述API响应
interface ApiResponse<T> {
  data: T;
  status: number;
  statusText: string;
}

接下来,创建一个泛型函数apiRequest,它接受一个ApiRequestConfig对象,并返回一个Promise,该Promise解析为定义的ApiResponse类型的实例:

// 泛型API请求函数
async function apiRequest<T>(config: ApiRequestConfig): Promise<ApiResponse<T>> {
  const response = await fetch(config.url, {
    method: config.method,
    headers: config.headers,
    body: config.body ? JSON.stringify(config.body) : null,
  });

  if (!response.ok) {
    throw new Error(`API request failed with status ${response.status}`);
  }

  const data: T = await response.json();
  return {
    data,
    status: response.status,
    statusText: response.statusText,
  };
}

接下来就可以重用apiRequest函数来处理不同类型的API调用。

例如,如果想要获取用户列表,可以这样做:

// 定义用户类型
interface User {
  id: number;
  name: string;
  email: string;
}

// 使用apiRequest函数获取用户列表
async function fetchUsers(): Promise<ApiResponse<User[]>> {
  const requestConfig: ApiRequestConfig = {
    url: 'https://api.example.com/users',
    method: 'GET',
  };
  return apiRequest<User[]>(requestConfig);
}

结论

通过学习 TypeScript 的函数类型,能更好地编写类型安全和可维护的代码。