【TypeScript】函数的类型定义

简言

函数是js的重要的一个基础构件,所以TypeScript 有许多方法来描述如何调用函数。让我们来学习如何编写描述函数的类型。

函数类型定义

函数一般包括函数名、参数和返回值,这些都需要类型定义。

函数声明类型

函数有多种声明方式,例如函数表达式、new声明(构造函数)之类的。
函数表达式类型定义:

//  最简单
type Fn = () => void
//  带参数,不返回值
type Fn2 = (a: string) => void
//  使用泛型
type Fn3 = <T>(a: T) => T

泛型下面会涉及,可以简单理解为需要使用时设置值的变量。

还有一种以对象类型定义函数的方式,这种方式可以定义函数的属性类型。

type DescribableFunction = {
  description: string;
  (someArg: number): boolean;
};
function doSomething(fn: DescribableFunction) {
  console.log(fn.description + " returned " + fn(6));
}

function myFunc(someArg: number) {
  return someArg > 3;
}
myFunc.description = "default description";

doSomething(myFunc);

JavaScript 函数也可以使用 new 操作符调用。TypeScript 将这些函数称为构造函数,因为它们通常会创建一个新对象。您可以在调用签名前添加 new 关键字来编写构造签名。
new 声明创建的函数类型定义:

//  new 
type F = {
  s:string
  new (a: string) : string
}
function fn(ctor: F) {
  return new ctor("hello");
}

参数类型

函数中的参数相当于变量,所以类型定义方式和变量相同。

默认值类型

函数参数可以赋一个默认值,此时参数的类型就相当于默认值的类型,当然你也可以在此基础上定义包含默认值类型的类型。

function fn(a: string | number = 1, b = 1) {
  console.log(a, b);
}

可选参数类型

js中定义好的参数可以使用时不传参的,这就有代码安全的隐患。
ts中参数没有定义默认类型为any,且必传,如果你希望参数可传可不传,需要使用可选符号?。

function fn2(a: string | number = 1, b?: number) {
  console.log(a, b);
}
fn2(1, 1)
fn2(1)
fn2(1, undefined)

如果是可选的,它有个默认类型undefined.
在为回调编写函数类型时,切勿编写可选参数,除非您打算在不传递该参数的情况下调用函数.

剩余参数类型

在 TypeScript 中,这些参数的类型注解隐含为 any[],而不是 any,并且给出的任何类型注解都必须是 Array<T> 或 T[],或者是元组类型。

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

返回值类型

函数返回值也需要类型定义。

没有返回值

函数没有返回值,默认返回值是void类型,你可以显示指定也可以不指定。

function fn(a: string | number = 1, b = 1,):void {
  console.log(a, b);
}
function fn2(a: string | number = 1, b?: number) {
  console.log(a, b);
}

有返回值

返回值也和变量类型定义一样,只不过类型需要在()之后定义。


function f1(): number {
  return 1
}
function f2(): string {
  return 'zsk6'
}
function f3(): string[] {
  return ['zsk6']
}

泛型

在 TypeScript 中,泛型用于描述两个值之间的对应关系。
它通常搭配函数使用,在函数中表示一个预设的类型值(使用箭头括号预设),然后在使用函数时指明这个类型值(使用箭头括号指定)。
例如:

function fn<Type>(s: Type) {
  console.log(s)
}

fn("hello")	//	Type = string
fn<number>(123)	//	Type = number
fn<Array<number> | number[]>([1, 2, 3])

fn函数预设了一个泛型Type,然后参数s的类型定义为Type,在函数时,参数s的类型就需要符合指定类型的范围了,当然可以直接传参数值,这样Type就自动推断为参数值的类型。

使用泛型的效果就是保证了函数的通用性,不需要过多设置参数范围,仅仅只需要预设一个类型值就行。

多个泛型类型

泛型类型可以为多个,用逗号分开即可

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

function map2<Input, Output, Other>(arr: Input[], func: (arg: Input) => Output, other: Other): Output[] {

  console.log(other);

  return arr.map(func);
}

map2<string, number, boolean>(["1", "2", "3"], (n) => parseInt(n), true);

泛型约束

我们编写了一些通用函数,可以对任何类型的值进行操作。有时,我们想将两个值联系起来,但只能对特定值的子集进行操作。在这种情况下,我们可以使用约束来限制类型参数可以接受的类型。
使用 extends 关键词进行泛型类型约束。

//	约束为带length属性的泛型
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);	//	报错

函数重载

有些 JavaScript 函数可以以多种参数数量和类型调用。例如,您可以编写一个生成 Date 的函数,该函数既可以使用时间戳(一个参数),也可以使用月/日/年规格(三个参数)。

在 TypeScript 中,我们可以通过编写重载签名来指定可以不同方式调用的函数。为此,请编写一定数量的函数签名(通常为两个或更多),然后在函数主体后编写。

//  重载
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);  //  1个参数
const d2 = makeDate(5, 5, 5);  //  3个参数
const d3 = makeDate(1, 3);  //  2个参数 报错

函数重载声明和函数实现声明参数要兼容

函数重载场景不多,大多数使用联合就行。

其他类型

在使用函数类型时,您还需要认识一些经常出现的额外类型。与所有类型一样,您可以在任何地方使用它们,但这些类型与函数尤其相关。

void

void 表示不返回值的函数的返回值。当函数没有任何返回语句,或没有从这些返回语句中返回任何显式值时,它就是推断类型:

// The inferred return type is void
function noop() {
  return;
}

在 JavaScript 中,不返回任何值的函数将隐式返回值 undefined。但在 TypeScript 中,void 和 undefined 并不相同。这两个是两个类型。

object

特殊类型对象指的是任何非基元(字符串、数字、大整数、布尔、符号、空或未定义)值。它不同于空对象类型 { },也不同于全局类型 Object。


function fn(o: object) {
  console.log(o);
}
fn({})
fn(() => { })
fn(new Date())
fn(new Set())
fn(new Map())
fn([1, 2])

请注意,在 JavaScript 中,函数值就是对象:它们有属性,原型链中有 Object.prototype,是 Object 的实例,可以调用 Object.keys 等等。因此,函数类型在 TypeScript 中也被视为对象。

unknown

未知类型代表任何值。它与 any 类型类似,但更安全,因为对未知值做任何操作都是不合法的。
意思就是 unknown类型的值只能看,不能做任何操作。

function fn2(u: unknown) {
  console.log(u);
}
fn2(1)
fn2('zsk6')

fn2({})
fn2(() => { })
fn2(new Date())
fn2(new Set())
fn2(new Map())
fn2([1, 2])

never

有些函数从不返回值:

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

never型表示从未观察到的值。在返回类型中,这意味着函数会抛出异常或终止程序的执行。

当 TypeScript 确定一个联合体中没有剩余值时,never 也会出现.

function fn(x: string | number) {
  if (typeof x === "string") {
    // do something
  } else if (typeof x === "number") {
    // do something else
  } else {
    x; // has type 'never'!
  }
}

Function

全局类型 Function 描述了 JavaScript 中所有函数值的绑定、调用、应用等属性。它还有一个特殊属性,即 Function 类型的值总是可以被调用;这些调用会返回 any类型。

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

这是一个未类型化的函数调用,通常最好避免使用,因为任何返回类型都是不安全的.

如果您需要接受一个任意函数,但不打算调用它,通常使用 () => void 类型更安全。

结语

结束了。

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZSK6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值