Skip to content
Published at:

More on Functions

Function Type Expressions

函数类型表达式, 语法:(a: string) => void

ts
function greeter(fn: (a: string) => void) {
  fn('Hello, World');
}

function printToConsole(s: string) {
  console.log(s);
}

greeter(printToConsole);

给一个函数类型起一个类型别名

ts
type GreetFunction = (a: string) => void;
function greeter(fn: GreetFunction) {
  // ...
}

Call Signatures

函数调用签名

ts
type DescribableFunction = {
  description: string;
  (someArg: number): boolean;
};

function doSomething(fn: DescribableFunction) {
  console.log(fn.description + ' returned ' + fn(6));
}

function myFunc(someArg: number) {
  return someArg > 3;
}

// key: myFunc 变成 DescribableFunction 类型
myFunc.description = 'default description';
doSomething(myFunc);

Construct Signatures

构造函数签名

ts
type SomeConstructor = {
  new (s: string): SomeObject;
};

function fn(ctor: SomeConstructor) {
  return new ctor('hello');
}

Generic Functions

泛型函数

ts
// normal function
function firstElement(arr: any[]) {
  return arr[0];
}

// Generic Functions
function firstElement<Type>(arr: Type[]): Type | undefined {
  return arr[0];
}

const s = firstElement(['a', 'b', 'c']); // string
const n = firstElement([1, 2, 3]); // number
const u = firstElement([]); // undefined

Inference

自动类型推导

ts
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
  return arr.map(func);
}

// Input: string
// Output: number
const parsed = map(['1', '2', '3'], (n) => parseInt(n));

Constraints

约束: extends 关键字

ts
function longest<Type extends { length: number }>(a: Type, b: Type) {
  if (a.length >= b.length) {
    return a;
  } else {
    return b;
  }
}
const longerArray = longest([1, 2], [1, 2, 3]); // Ok
const longerString = longest('alice', 'bob'); // Ok
const notOK = longest(10, 100); // Error: number类型没有 length 成员属性

Specifying Type Arguments

ts
function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
  return arr1.concat(arr2);
}

// Error: 识别到第一个参数时,自动推导 Type 为number;第二个参数string数组就会报错
const arr = combine([1, 2, 3], ['hello']); 

// Ok: 调用时指定类型
const arr = combine<string | number>([1, 2, 3], ['hello']);

Guidelines for Writing Good Generic Functions

Push Type Parameters Down

ts
function firstElement1<Type>(arr: Type[]) {
  return arr[0];
}

// 抽象
function firstElement2<Type extends any[]>(arr: Type) {
  return arr[0];
}

// a: number (good)
const a = firstElement1([1, 2, 3]);
// b: any (bad)
const b = firstElement2([1, 2, 3]);

Use Fewer Type Parameters

ts
function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
  return arr.filter(func);
}

// 更难阅读
function filter2<Type, Func extends (arg: Type) => boolean>(arr: Type[], func: Func): Type[] {
  return arr.filter(func);
}

Type Parameters Should Appear Twice

ts
function greet<Str extends string>(s: Str) {
  console.log('Hello, ' + s);
}
greet('world');

// 只使用一次,可以写成更简单的方式
function greet(s: string) {
  console.log('Hello, ' + s);
}

Optional Parameters

可选参数:

ts
// 使用`?`问号表示可选参数
function f(x?: number) {
  // ...
}
f(); // OK
f(10); // OK
f(undefined); // OK

// 给参数设置默认值
function f(x = 10) {
  // ...
}

Optional Parameters in Callbacks

回调中的可选参数

ts
function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
  for (let i = 0; i < arr.length; i++) {
    callback(arr[i], i);
  }
}

myForEach([1, 2, 3], (a) => console.log(a));
myForEach([1, 2, 3], (a, i) => console.log(a, i));

Function Overloads

ts
// 两个是重载函数
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
// 函数实现:
//  - 参数要兼容选项函数
//  - 返回值得一样
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}

const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3); // Error: 必须使用重载函数中的一种

Other Types to Know About

  • void
  • object
  • unknown
  • never
  • Function

void

void描述函数不返回值

never

用在函数返回值,表示函数永远不会返回

ts
function fail(msg: string): never {
  throw new Error(msg);
}
ts
// The inferred return type is void
function noop() {
  return;
}

Rest Parameters and Arguments

Rest Parameters

剩余参数

ts
function multiply(n: number, ...m: number[]) {
  return m.map((x) => n * x);
}
// 'a' gets value [10, 20, 30, 40]
const a = multiply(10, 1, 2, 3, 4);

Rest Arguments

剩余传数

ts
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr1.push(...arr2);

Parameter Destructuring

参数解构

ts
function sum({ a, b, c }: { a: number; b: number; c: number }) {
  console.log(a + b + c);
}

// 同上
type ABC = { a: number; b: number; c: number };
function sum({ a, b, c }: ABC) {
  console.log(a + b + c);
}