[ts]函数

25 阅读3分钟

官网地址

函数类型

type GreetFunction = (a: string) => void;

function greeter(fn: GreetFunction) {
    // ...
}

调用签名

type DescribableFunction = {
    description: string;
    // 是对象类型,所以是`:`,而不是`=>`
    (someArg: number): boolean;
};

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

函数可以有自己的属性,但是函数类型表达式不能声明属性,可以使用对象类型来表示调用签名。

构造签名

js中的函数可以通过new操作符来当做构造函数调用。

type SomeConstructor = {
    // 调用签名前添加new
    new (s: string): SomeObject;
};


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

还有一些对象,既可以当做普通函数调用,也可以当做构造函数调用,比如像Date

interface CallOrConstruct {
    new (s: string): Date;
    (n?: number): number;
}

泛型函数

在ts中,泛型用来描述2个值之间的一致性。使用Type类型参数,使入参出参建立了联系。调用时,ts可以推断出更具体的类型。

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

// s is of type 'string'
const s = firstElement(["a", "b", "c"]);

// n is of type 'number'
const n = firstElement([1, 2, 3]);

// u is of type undefined
const u = firstElement([]);

接口

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

 
// Parameter 'n' is of type 'string'
// 'parsed' is of type 'number[]'
const parsed = map(["1", "2", "3"], (n) => parseInt(n));

类型约束

可以使用extends来约束泛型类型

function longest<Type extends { length: number }>(a: Type, b: Type) {
    if (a.length >= b.length) {
        return a;
    } else {
        return b;
    }
}

 

// longerArray is of type 'number[]'
const longerArray = longest([1, 2], [1, 2, 3]);

// longerString is of type 'alice' | 'bob'
const longerString = longest("alice", "bob");

// Error! Numbers don't have a 'length' property
const notOK = longest(10, 100);

指定参数类型

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

// Type 'string' is not assignable to type 'number'.
const arr = combine([1, 2, 3], ["hello"]);

// 手动指定类型
const arr = combine<string | number>([1, 2, 3], ["hello"]);

参数可选

function f(x?: number) {
    // ...
}

f(); // OK
f(10); // OK

重载

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);

多个重载签名,一个实现签名(需要兼容重载签名)

申明this

interface DB {
    filterUsers(filter: (this: User) => boolean): User[];
}

 

const db = getDB();
const admins = db.filterUsers(function (this: User) {
    return this.admin;
});

有些场景下,ts不能推导出this的指向,js规范规定不能使用this关键字当作形参,所以ts利用了这点,可以在入参中使用this关键字声明函数体中this的类型。

其他类型

void

函数没返回值,ts中voidundefined不一样。

object

object类型可以表示除了基本数据类型(stringnumberbigintbooleansymbolnull, undefined)外的任何类型。ts中函数也可以是object类型。

unknown

unknow类型可以代表任何一种类型,但是比any类型要安全。

never

function fail(msg: string): never {
    throw new Error(msg);
}

Function

function doSomething(f: Function) {
    return f(1, 2, 3);
}

避免使用,返回值是any类型。一般使用() => void

剩余参数、Arguments

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);
const args = [8, 5] as const;

// OK
const angle = Math.atan2(...args);

参数解构

function sum({ a, b, c }: { a: number; b: number; c: number }) {}


// 或者
type ABC = { a: number; b: number; c: number };
function sum({ a, b, c }: ABC) {}

Assignability of Functions

type voidFunc = () => void;

const f1: voidFunc = () => {
    return true;
};

const f2: voidFunc = () => true;
const f3: voidFunc = function () {
    return true;
};

当函数的类型是type vf = () => void,实现时可以返回任何一个值。

function f2(): void {
    // @ts-expect-error
    return true;
}
 
const f3 = function (): void {
    // @ts-expect-error
    return true;
};

定义函数时,返回类型是void时,不能返回任何值,否则ts会报错。