函数类型
在ts中声明函数时与js不同,需要显式声明参数类型和返回值类型
类型声明
语法为:(参数名: 参数类型) => 返回值类型
// fn是一个要求参数类型为string,返回值类型为boolean的函数
const doSomething = (fn: (arg: string) => boolean): void => {
fn('hello world')
}
通用声明
更加通用的函数类型声明
type Fun = (...args: any[]) => any
interface Fun2 {
(...args: any[]): any
}
带属性的函数声明
但是在js中会存在包含一些属性的函数,即将属性挂到声明的函数类型的变量上
const fn = function (name: string) {
console.log('hello ' + name)
}
fn.desc = '我是一个函数'
在ts中可以如下声明来解决上述问题:
type fn = {
desc: string,
(name: string): void
}
interface fn{
desc: string,
(name: string): void
}
需要注意的是这与不含属性的函数类型有些许不同,参数类型与返回值类型之间一个是:
另一个是=>
:(name: string): void
(arg: string) => boolean
构造函数声明
在js中可以实例化函数,对应的在ts中可以声明如下:
type Fn = {
new(s: string): SomeObject;
};
function fn(ctor: Fn) {
return new ctor("hello");
}
TIP
可以将两者组合使用,日期:Date便是一个例子,既可以实例化,又可以直接调用。
返回值类型
可以显示的声明返回值类型,如果没有声明,ts则会尝试自行根据返回值推断类型。
const getName = (): string => {
return 'xiaoming'
}
只要是ts允许的类型都可以作为返回值类型,只特别介绍void
类型
void类型
如果函数没有返回值或者返回undefined
,则返回值类型为void
const sayHello = (): void => {
console.log('hello world')
}
通过type alias声明的函数
此时void
表示会忽略返回值
type voidFunc = () => void;
const f1: voidFunc = () => {
return true;
};
const f2: voidFunc = () => true;
const f3: voidFunc = function () {
return true;
};
这是为了兼容没有函数体的回调['1', '2', '3'].forEach( (item) => parseFloat(item))
forEach
的返回值类型为void,但是parseFloat的返回值类型是number
,但是这在ts中并不报错。
字面函数声明
此时不能有返回值或者返回undefined
const f2 = function (): void {
}
const f3 = function (): void {
return undefined
}
泛型
为了使函数更加通用,可以传入一个或多个泛型(类型变量),在声明参数类型和返回值类型时可以使用泛型来声明
//
function map<Input, Output>(data: Input[], callback: (item: Input, index: number) => Output): Output[] {
return data.map(callback)
}
WARNING
如果返回值类型和参数类型分配了同一个泛型类型,则返回值必须与入参的值的类型必须相同,而不能是其他泛型的子类。
在定义函数的泛型时,根据官方推荐的规则总结出以下判断:
- 需要声明泛型时,尽量使用它本身,而不是通过extends约束它
- 尽可能使用少量的类型参数
- 不要为回调函数声明可选参数,即使是可选的
参数类型
为函数的参数列表分配类型,语法类似声明对象属性。如果没有显式声明,ts会默认为any
const sayHello = (name: string) => {
console.log('i am ' + name)
}
可选参数
ts默认所有参数都是必须的,但是可以通过?
表明参数是非必须的
// 被`?`标记的参数的类型为:number | undefined
function add(a: number, b: number, c?: number) {
return a + b + (c || 0);
}
参数默认值
默认值写在参数类型之后
function add(a: number, b: number, c: number = 10) {
return a + b + (c || 0);
}
具名参数
含义等于解构对象参数
function introduce({name, age}: { name: string, age: number }) {
console.log(name + ':' + age)
}
剩余参数
...
将剩余参数列表归纳为数组,这点与js保存一致,但是需要声明剩余参数列表的类型
function add(a: number, b: number, ...rest: number[]) {
return a + b + rest.reduce((p, c) => p + c, 0);
}
类型别名
为函数类型的变量声明一个类型
type Introduce = (name: string) => string
const introduce: Introduce = (name) => {
return name
}
重载
函数名相同但是参数列表的个数、类型、顺序不同,返回值不同的称为函数的重载
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);
}
}
在声明了函数的不同签名时,由于只能有一个实现,所以实现函数时需要兼容不同的版本。
在上面的函数实现中,d
和y
为可选参数,在添加函数体时对未传d
和y
的情况区分了处理。
TIP
能使用联合类型时,尽量不要使用函数的重载
类型收敛
将宽泛的类型收敛为一个更为精确的类型
type predicate
语法为:参数名 is
类型
当使用类型断言函数作为返回值类型时,返回值类型必须为boolean
function isValidRating(
rating: any
): rating is Rating {
if (!rating || typeof rating !== "number") {
return false;
}
return (
rating === 1 ||
rating === 2 ||
rating === 3 ||
rating === 4 ||
rating === 5
);
}