函数(在对象中又叫做方法),是编码中最普遍存在和使用的一种对象。本节学习如何在 TypeScript 中声明函数,方便我们开发。
下面将从以下 6 个方面来讲:类型表达式、调用签名、构造签名、函数重载、泛型函数、可选参数。
一、类型表达式(Function Type Expressions)
函数类型表达式(Function Type Expressions)是最简单声明函数的方式。语法类似 (s: string) => void
,使用胖箭头(=>
)分隔参数列表和返回值类型。
function greeter(fn: (s: string) => void) {
fn('Hello Wolrd');
}
二、调用签名(Call Signatures)
这是为了满足声明那些包含属性的函数。JavaScript 中函数就是一类特殊的对象。
比如我们有一个函数 doSomething
,接收一个函数类型参数 fn
,fn
类型如下:
-
接收一个数值类型 number
的参数调用,返回布尔类型 -
还包含一个字符串类型属性 description
type CallableFunc = {
decription: string;
(arg: number): boolean
}
function doSomething(fn: CallableFunc) {
fn.decription;
fn(123);
}
注意,这里声明函数使用的是冒号 :
而非胖箭头 =>
,对象类型中是采用 k: v
形式指定键值对的。
三、构造签名(Construct Signatures)
构造函数声明类似函数调用声明,不过多了一个 new
前缀。
type Ctor = {
new (s: string): Date;
}
function fn(ctor: Ctor) {
new ctor('hello');
}
当然,调用签名和构造签名可以同时使用,
type Ctor = {
new (s: string): Date;
(n: number): Date;
}
function fn(ctor: Ctor) {
new ctor('hello');
ctor(12315);
}
四、函数重载(Function Overloads)
有时某个函数可能要支持不同参数的调用形式。假设有一个函数 makeDate()
来说:
-
既支持通过时间戳( number
类似)来创建日期对象 -
也支持通过月( m
)、日(d
)、年(y
)来创建日期对象
如何定义这个 makeDate()
函数?
// Error: Duplicate function implementation.ts(2393)
function makeDate(timestamp: number): Date {}
function makeDate(m: number, d: number, y: number): Date {}
这时候就要用到函数重载了。
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrtimestamp: number, d?: number, y?: number) {
if (d !== undefined && y !== undefined) {
return new Date(y, mOrtimestamp, d);
}
return new Date(mOrtimestamp);
}
五、泛型函数(Generic Functions)
设想这样一个场景,我有一个函数,获取数组的第一个元素。返回值类型取决于传入的数组。
比如:传入的是 number[]
类型,那么返回 number
;传入的是 string[]
类型,那么返回 string
。
我们可以用函数重载来实现:
function firstElem(arr: number[]): number | undefined;
function firstElem(arr: string[]): string | undefined;
function firstElem(arr: number[] | string[]): string | number | undefined {
return arr[0];
}
firstElem([1, 2, 3, 4]);
firstElem(['1', '2', '3', '4']);
但不够灵活。因为返回值类型取决于传入的数组,所以我们可以抽象出一个泛型 T
来表示数组元素类型。
function firstElem2<T>(arr: T[]): T | undefined {
return arr[0];
}
firstElem2([1, 2, 3, 4]);
firstElem2(['1', '2', '3', '4']);
firstElem2([true, false]);
泛型 T
是一种特殊的类型,依赖实际调用场景。函数中泛型的声明放在函数名之后,用尖括号 <>
包裹。
对应到本例,我们声明了一个函数 firstElem2
,其接收一个元素类型为“T”的数组,函数返回值类型关联数组元素类型——返回 T
(有元素) 或者 undefined
(无元素)。
当我们使用 [1, 2, 3, 4]
调用 firstElem2()
函数时,TypeScript 推导泛型 T
即是 number
类型,继而推导返回类型为 number | undefiend
。后续使用 ['1', '2', '3', '4']
以及 [true, false]
调用,原理类似。
使用泛型可以简化我们的函数类型声明。
当然,还能「同时使用多个泛型、对泛型类型做约束」:
-
使用多个泛型
泛型间使用逗号隔开。
function map<Input, Output>(arr: Input[], fn: (input: Input) => Output): Output[] {
return arr.map(fn);
}
map([1,2,3], (num) => num * 2);
map([1,2,3], (num) => `${ num }`);
-
对泛型类型做约束
使用 extends
关键字来约束泛型范围。
function longest<T extends { length: number }>(a: T, b: T) {
if (a.length >= b.length) {
return a;
} else {
return b;
}
}
longest([1], [2, 3]);
longest('1', '2');
// Error: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
// longest(1, 2);
六、可选参数(Optional Parameters)
与在 interface
中声明对象类型的可选属性类似,可选参数也是使用的 ?:
// 必填参数
function f(num: number) {}
// Error: Expected 1 arguments, but got 0.
// f();
f(1);
// 可选参数
function f2(num?: number) {
// Error: 'num' is possibly 'undefined'.
// num.toFixed();
}
f2();
f2(1);
// 参数默认值
function f3(num = 10) {
num.toFixed();
}
原文始发于微信公众号(写代码的宝哥):TypeScript 中如何声明函数?
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/244045.html