跳到主要内容

函数

interface 可以用来声明函数

interface 也可以用来约束 ts class,但是使用 implements 关键字

// 对函数的声明
interface MyFunc {
(param1: string, param2: number): boolean;
}

let func: MyFunc;
func = (param1: string, param2: number) => true;

// 对类的声明
interface MyClassConstructor {
// 覆盖new
new (prop1: string, prop2: number);

myMethod(param1: string): void;
}



// 用implements关键字才能bind类和接口
class MyClass implements MyClassConstructor {
constructor(prop1: string, prop2: number) {
// construct code.
}
myMethod(param1: string) {
// method code.
}
}

函数类型直接声明

两种, 第一种箭头表达需要变量接住 第二种直接用 function 声明,不需要使用箭头

const fun1: (a: number) => number = (a) => {
return a;
};

function fun2(a: number): number {
return a;
}

// 匿名函数
const fun3 = function (a: number) {
// TS会根据函数体的代码infer出返回值为number类型
return a;
};

大部分情况返回结果可以直接推导 当你需要对函数的返回值进行严格限制,以保证在以后的更新中能够避免函数中新增 return 分支不符合期望输出的要求时,建议并且应当对返回值类型进行显式的声明

除了前面使用 interface 书写函数的 Type,还可以用以下方式,也更推荐使用这种方式(type):

type MyFunc = (param1: string, param2: number) => boolean;

let myFunc: MyFunc;
myFunc = (param1: string, param2: number) => true;

type+{()}

type FooFunc = {
(arg: string): boolean;
}

这种方式的好处是可以往函数对象上挂东西:

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


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

不要在 type 或 interface 中使用函数声明

保持一致性,类型/接口的所有成员都通过相同的语法定义。 --strictFunctionTypes 在比较函数类型时强制执行更严格的类型检查,但第一种声明方式下严格检查不生效。


interface ICounter {
start: (value: number) => string
}

interface ICounter1 {
start(value: number): string
}


🌰
interface Animal {}
interface Dog extends Animal {
wow: () => void
}


interface Comparer<T> {
compare: (a: T, b: T) => number
}
declare let animalComparer: Comparer<Animal>
declare let dogComparer: Comparer<Doganimal>
Comparer = dogComparer // Error
dogComparer = animalComparer // Ok


interface Comparer1<T> {
compare(a: T, b: T): number
}
declare let animalComparer1: Comparer1<Animal>
declare let dogComparer1: Comparer1<Doganimal>
Comparer1 = dogComparer // Ok
dogComparer1 = animalComparer // Ok

如果函数参数是可选值的情况

// 建议将可选参数尽可能地放在参数列表的靠后的位置, 不然取的时候要取空值,或者结构设置placeholder
type MyFunc = (param1: string, param2?: number) => void;
// 给参数设定默认值
type MyFunc2 = (param1: string, param2 = 0) => void;

如果参数的数量不确定

// 前若干参数确定,但后续参数不确定
type MyFunc = (p1: string, p2: number, ...rest: (string | number)[]) => void;
// Array.push type
// 先将参数用扩展运算符合成为一个数组,再定义类型T[]
ArrayPush = <T>(...items: T[]) => number;

如果参数有很多,并且都是确定的

不推荐直接在参数列表罗列出所有这些参数,更好的实践方案是将这些参数放到一个 object 中进行传递,而对这个 object 的声明,建议提取成 interface

这样做是为了让我们的函数定义显得更加清晰,并且在未来需要添加更多参数时,能够更加地方便快捷。

interface IOptions {
foo: string;
bar?: number;
foofoo: boolean;
// ...more options
// also using index to support dynamic options
[optionKey: string]: any;
}

type MyFunc = (options: IOptions) => void;

// 在取参数的时候,可以考虑使用解构的形式来进行
function myFunc({
foo,
bar = 100, // 使用这种方式在设定缺省值
foofoo,
...rest
}: IOptions) {
// function body.
}

要对函数的 this 进行声明

ActualThisType

function MyFunc(this: ActualThisType, param1: string, param2: number) {
this; // ActualThisType
}

需要显式声明 this 的类型的情况,一般是在代码逻辑中,我们将函数的上下文进行了重新绑定时。 箭头函数不能显式地声明 this,毕竟箭头函数没有属于自己的 this。

重载函数

当我们的函数逻辑需要对参数进行重载时,先用 widest 的声明方案来对函数进行实现,然后在函数的实现部分紧邻的上方对重载的形式进行额外的声明,重载部分的声明必须是实现部分声明的 sub case:

function emit(eventName: 'event1', param1: string, param2: number): void;
function emit(eventName: 'event2', param1: boolean): void;
function emit(eventName: string, ...params: any[]): void {// function implements.
}

// 对类方法的重载写法
class MyClass {
// this支持链式调用
on(eventName: 'event1', eventListener: (param1: string, param2: number) => void):this;
on(eventName: 'event2', eventListener: (param1: boolean) => void): this;
on(eventName: string, eventListener: (...params: any[]) => void): this {
// method implements.
}
}