前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >函数_TypeScript笔记5

函数_TypeScript笔记5

作者头像
ayqy贾杰
发布2019-06-12 15:08:13
7770
发布2019-06-12 15:08:13
举报
文章被收录于专栏:黯羽轻扬

一.类型

函数的类型分为两部分:

  • 参数:各个参数的类型
  • 返回值:返回值的类型

例如:

代码语言:javascript
复制
// 具名函数
function add(x: number, y: number): number {
   return x + y;
}// 匿名函数
let myAdd = function(x: number, y: number): number { return x + y; };

带类型的函数声明足够表达一个函数的类型信息,但无法复用。那么有办法复用一个函数的类型吗?

有。把类型抽离出来就可以复用了,姑且称之为类型描述

类型描述

可以通过箭头函数语法描述函数的类型:

代码语言:javascript
复制
let myAdd: (x: number, y: number) => number =
   function(x: number, y: number): number { return x + y; };

箭头(=>)左侧是参数及其类型,右侧是返回值类型,都是语法结构的一部分,不可缺省

代码语言:javascript
复制
// 无返回值
let log: (msg: string) => void = function(msg) {
 console.log(msg);
};
// 无参数
let createLogger: () => object = function() {
 return { log };
};
// 既无参数也无返回值
let logUa: () => void = log.bind(this, navigator.userAgent);

P.S.注意到上面示例只声明了一份类型,是因为右边匿名函数的类型能够根据左侧类型声明自动推断出来,称之为语境类型推断(contextual typing)

另外,类型描述里的参数名只是可读性需要,不要求类型描述中的参数名与真实参数名一致,例如:

代码语言:javascript
复制
let myAdd: (baseValue: number, increment: number) => number =
   function(x: number, y: number): number { return x + y; };

P.S.实际上,还有另一种描述函数类型的方式:接口,具体见接口_TypeScript笔记3

二.参数

可选参数

JavaScript里参数默认都是可选的(不传的默认undefined),而TypeScript认为每个参数都是必填的,除非显式声明可选参数:

代码语言:javascript
复制
function buildName(firstName: string, lastName?: string) {
   if (lastName)
       return firstName + " " + lastName;
   else
       return firstName;
}

与可选属性的语法类似,紧跟在参数名后面的?表示该参数可选,并且要求可选参数必须出现在必填参数之后(所以想要firstName可选,lastName必填的话,只能改变参数顺序)

默认参数

默认参数语法与ES规范一致,例如:

代码语言:javascript
复制
function buildName(firstName: string, lastName = "Smith") {
   return firstName + " " + lastName;
}

从含义上看,默认参数当然是可选的(不填就走默认值),因此,可以认为默认参数是特殊的可选参数,甚至连类型描述也是兼容的:

代码语言:javascript
复制
let buildName: (firstName: string, lastName?: string) => string;
// 可选参数
buildName = function(firstName: string, lastName?: string) {
   if (lastName)
       return firstName + " " + lastName;
   else
       return firstName;
};
// 默认参数
buildName = function(firstName: string, lastName = "Smith") {
   return firstName + " " + lastName;
};

二者类型完全一致,所以,类型描述并不能完整表达默认参数(仅能表达出可选的含义,默认值丢失了)

另一个区别是,默认参数不必出现在必填参数之后,例如:

代码语言:javascript
复制
function buildName(firstName = "Will", lastName: string) {
   return firstName + " " + lastName;
}buildName(undefined, "Adams");

显式传入undefined占位,具体见三.默认参数

剩余参数

与ES6不定参数语法一致:

代码语言:javascript
复制
function buildName(firstName: string, ...restOfName: string[]) {
   return firstName + " " + restOfName.join(" ");
}let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

剩余参数也是可选的,相当于不限数量的可选参数

Rest parameters are treated as a boundless number of optional parameters.

另外,类型描述中也采用了相同的语法:

代码语言:javascript
复制
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

三.this

this在JavaScript不那么容易驾驭,例如:

代码语言:javascript
复制
class Cat {
 constructor(public name: string) {}
 meow() { console.log(`${this.name} meow~`); }
}let cat = new Cat('Neko');
// 点击触发的log中,name丢了
document.body.addEventListener('click', cat.meow);

this的类型

特殊的,TypeScript能够描述this的类型,例如:

代码语言:javascript
复制
class Cat {
 constructor(public name: string) {}
 meow(this: Cat) { console.log('meow~'); }
}class EventBus {
 on(type: string, handler: (this: void, ...params) => void) {/* ... */}
}new EventBus().on('click', new Cat('Neko').meow);

其中this是个假参数,并且要求必须作为第一个参数:

this parameters are fake parameters that come first in the parameter list of a function.

this也像普通参数一样进行类型检查,能够提前暴露出类似的错误:

Argument of type ‘(this: Cat) => void’ is not assignable to parameter of type ‘(this: void, …params: any[]) => void’.

P.S.另外,可以开启--noImplicitThis编译选项,强制要求所有this必须有显式的类型声明

四.重载

类似于Java里的重载:

Method Overloading: This allows us to have more than one method having the same name, if the parameters of methods are different in number, sequence and data types of parameters.

(摘自Types of polymorphism in java- Runtime and Compile time polymorphism)

简言之,能让同名函数的不同版本共存。不同版本体现在参数差异上:

  • 参数数量
  • 参数顺序
  • 参数类型

这3个特征中只要有一个不同就算重载。如果都相同,就认为是重复声明的方法(Duplicate Method),并抛出编译错误:

代码语言:javascript
复制
// Java
public class Addition {
 // Compile Time Error - Duplicate method sum(int, int)
 int sum(int a, int b) {
   return a+b;
 } // Compile Time Error - Duplicate method sum(int, int)
 void sum(int a, int b) {
   System.out.println(a+b);
 }
}

TypeScript里也有重载的概念,但与Java重载有一些差异,例如:

代码语言:javascript
复制
class Addition {
 sum(a: number, b: number): number {
   return a + b;
 } sum(a: number[]): number {
   return a.reduce((acc, v) => acc + v, 0);
 }
}

看起来非常合理,但在TypeScript里会报错:

Duplicate function implementation.

编译结果是这样(TypeScript编译报错并不影响代码生成,具体见类型系统):

代码语言:javascript
复制
var Addition = /** @class */ (function () {
   function Addition() {
   }
   Addition.prototype.sum = function (a, b) {
       return a + b;
   };
   Addition.prototype.sum = function (a) {
       return a.reduce(function (acc, v) { return acc + v; }, 0);
   };
   return Addition;
}());

因为JavaScript不支持重载,(同一作用域下的)方法会覆盖掉先声明的同名方法,无论函数签名是否相同。因此,TypeScript里的重载能力受限,仅体现在类型上

代码语言:javascript
复制
function sum(a: number, b: number): number;
function sum(a: number[]): number;
function sum(a, b?) {
   if (Array.isArray(a)) {
       a.reduce((acc, v) => acc + v, 0);
   }
   return a + b;
}

同样,这些重载类型声明仅作用于编译时,因此也有类似于模式匹配的特性:

代码语言:javascript
复制
function sum(a: any, b: any): any;
function sum(a: number, b: number): number;
function sum(a, b) {
   return Number(a) + Number(b);
}// 这里value是any类型
let value = sum(1, 2);

上例中先声明的更宽泛的any版本成功匹配,因此并没有如预期地匹配到更准确的number版本,

It looks at the overload list, and proceeding with the first overload attempts to call the function with the provided parameters. If it finds a match, it picks this overload as the correct overload.

所以,应该把最宽泛的版本放到最后声明

it’s customary to order overloads from most specific to least specific.

参考资料

  • Functions
  • Function Overloads in TypeScript
  • TypeScript function overloading
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-02-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端向后 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.类型
    • 类型描述
    • 二.参数
      • 可选参数
        • 默认参数
          • 剩余参数
          • 三.this
            • this的类型
            • 四.重载
              • 参考资料
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档