函数
函数的类型就是描述函数入参类型与函数返回值类型
函数的类型签名
函数声明:
function foo(name: string): number {
return name.length;
}
const bar = function (name: string): number {
return name.length;
};
1、使用 type
声明:
type FnProps = {
(a: string): string;
};
type FnProps = (a: string) => string;
const fn: FnProps = a => a;
2、使用 interface
声明:
interface FnProps {
a: () => string;
}
interface FnProps {
a(): string;
}
在 interface 中,推荐按照foo(): string;
的方式来定义方法,将属性和方法分开,因为它更直观、与类的方法声明方式一致。
interface Props {
foo(): string;
bar: () => void;
}
const obj: Props = {
foo() {
return 'hello';
},
bar: () => {}
};
参数注解
1. 内联类型注解
function fn1(a: string) {}
const fn2 = (a: string) => {};
const fn3: (a: string) => void = a => {};
type infoProps = (a: string) => void;
const fn4: infoProps = a => {};
2. 接口类型注解
interface Info {
name: string;
age: number;
}
function fn(prop: Info) {
return prop.name + prop.age;
}
fn({ name: 'zgh', age: 18 });
3. 可选参数
可选参数必须在必需参数后面
function fn(a: string, b?: string) {}
b 可以为 undefined,不能为 null
也可以将参数设置默认值,这样也是可 选参数
4. 参数设置默认值
function fn(name: string = 'zgh') {}
参数不能有问号和初始值设定项
5. rest 参数
使用any[]
或者元祖类型
function foo(arg1: string, ...rest: any[]) {}
function bar(arg1: string, ...rest: [number, string]) {}
bar('a', 1, 'b');
返回值注解
通常不需要给函数返回值添加注解,编译器会推断出来
// 没有返回值
function getInfo(): void {
console.log('This is message');
}
// 返回number
function getUser(a: number, b: number): number {
return a + b;
}
关于 void 类型:
// 当返回值是void时,不校验返回值
type FnProps = (a: string) => void;
const fn: FnProps = a => {
// 这里即使返回了值,也不会报错
return 1;
};
// 这样会报错
function gn(a: string): void {
return 1;
}
异步函数:Promise<T>
async function fn(): Promise<number> {
return new Promise((resolve, reject) => {
resolve(1);
});
}
函数重载
函数根据传入不同的参数而返回不同类型的数据。类型重载可以更好地表达函数的行为,在调用时提供更精确的类型检查。
定义函数的类型重载:
- 在函数实现之前,先声明多个函数签名
- 在最后一个签名之后,提供函数的具体实现
编译器会先从重载列表的第一个重载定义开始查找匹配项,直到选择出正确的检查类型。因此,在定义重载的时候,一定要把最精确的定义放在最前面。
假设有一个函数 f,如果传入参数是 string 类型,就返回 string 类型;如果是 number 类型,就返回 number 类型。利用联合类型,可以实现:
function f(x: string | number): string | number {
if (typeof x === 'string') {
return x;
} else if (typeof x === 'number') {
return x + 1;
}
return 0;
}
let a = f(1); // string | number
这样有一个缺点,就是定义不够精确,传入什么类型,输出也该是什么类型。如果只看function f(x: string | number): string | number {}
这部分,我们无法知道f
函数返回的是string
还是number
。这时就需要用到函数重载了。
function f(x: string): string;
function f(x: number): number;
function f(x: string | number): string | number {
if (typeof x === 'string') {
return x;
} else if (typeof x === 'number') {
return x + 1;
}
return 0;
}
let a = f(1); // number
这样改变后,重载的 f 函数在调用的时候会进行正确的类型检查。
函数签名和函数实现逻辑之间可以有空格,但是不能有其他代码。
function f(x: string): string;
function f(x: number): number;
// 不允许:let a = 1
function f(x: string | number): string | number {}
示例:有一个 format 函数可以格式化日期或数字
// 重载签名
function format(date: Date): string;
function format(number: number, precision: number): string;
// 函数实现
function format(value: Date | number, precision?: number): string {
if (value instanceof Date) {
return value.toDateString();
} else if (typeof value === 'number' && typeof precision === 'number') {
return value.toFixed(precision);
}
throw new Error('Invalid arguments');
}
const dateStr = format(new Date()); // 返回日期字符串
const numStr = format(3.14159, 7); // 返回 "3.1415900"