1 minute read

TypeScript 为 JavaScript 函数添加了额外的功能,让我们可以更容易地使用。

函数类型

为函数定义类型

函数类型包含两部分:参数类型和返回值类型

// 具名函数
function add(x: number, y: number): number {
    return x + y
}

// 匿名函数
let myAdd = function (x: number, y: number): number {
    return x + y
}

TypeScript 能够根据返回语句自动推断出返回值类型,因此我们通常省略它。

完整函数类型

给函数的参数指定名字和类型,增加可阅读性

// 先指明了 myAdd 的类型,然后是一个函数
let myAdd: (baseValue: number, increment: number) => number = function (
    x: number,
    y: number
): number {
    return x + y
}

只要参数类型匹配的,我们就认为他是有效的函数类型。返回值类型是函数类型的必要部分,如果函数没有返回值,必须指定返回值类型为void,而不能留空

可选参数和默认参数

TypeScript 里的每个参数都是必须的,编译器会检查用户是否传递了值,并且传递给函数的参数个数与函数的期望个数是否一致

let res = add(1, 2, 3) // Expected 2 arguments, but got 3
let res1 = add(1) // Expected 2 arguments, but got 1
let res2 = add(1, 2) // right

在 JavaScript 中如果我们某个参数不传值,则默认这个参数的值为undefined,但是在 TypeScript 中我们需要通过在参数名后面加 ? 来表示该参数是可选参数,可选参数必须放在必选参数的后面,这点很容易理解。

function add(x: number, y?: number): number {
    if (y) return x + y
    return x
}
let res = add(1) // right

当用户没有传递这个参数或者传递的参数为 undefined 时,我们可以为参数初始化一个默认值,这个在 es6 中已经有支持了,这点是一样的

function add(x: number, y = 1): number {
    return x + y
}
let res = add(1)

在所有必须参数后面的带默认初始化的参数都是可选的,与可选参数一样,在调用函数的时候可以省略。 也就是说可选参数与末尾的默认参数共享参数类型。带默认值的参数可以放在必选参数的前面,但是如果想要获得默认值,必须在调用的时候自己手动传递undefined

function add(x = 1, y: number) {
    return x + y
}
let res = add(undefined, 1)

剩余参数

这个与 es6 中的...一样的,剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个,名字是你在省略号( ...)后面给定的名字,你可以在函数体内使用这个数组。剩余参数必须放在必选参数后面。

function add(x: number, ...rest: number[]) {
    return rest
}
// 返回
let res = add(1, 2, 3, 4, 5) // [2,3,4,5]

this 和箭头函数

在 TypeScript 中如下使用 this

interface Card {
    suit: string;
    card: number;
}
interface Deck {
    suits: string[];
    cards: number[];
    createCardPicker(this: Deck): () => Card;
}
let deck: Deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    // NOTE: The function now explicitly specifies that its callee must be of type Deck
    createCardPicker: function (this: Deck) {
        return () => {
            let pickedCard = Math.floor(Math.random() * 52)
            let pickedSuit = Math.floor(pickedCard / 13)
            // 如果不在function的参数中这样指定this,当我们鼠标移到下面的this上显示的是 any,但是这样指定后就是Deck了
            return { suit: this.suits[pickedSuit], card: pickedCard % 13 }
        }
    },
}

let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()

alert("card: " + pickedCard.card + " of " + pickedCard.suit)

为什么显示为 any 呢?这是因为 this来自对象字面量里的函数表达式。 修改的方法是,提供一个显式的 this参数。 this参数是个假的参数,它出现在参数列表的最前面

重载

重载是面向对象语言实现多态的一种方式,所谓重载是指函数的名字一样,但是函数个参数个数或者类型不一致,我们在调用函数的时候,编译器会根据我们传递的参数去匹配对应的函数

function reloadFunc(a: number): void;

function reloadFunc(a: string): void;

function reloadFunc(a): any {
    console.log(`这是${typeof (a)}的重载函数`)
}

reloadFunc(1)
reloadFunc("2")
reloadFunc({})
/* Overload 1 of 2, '(a: number): void', gave the following error.
    类型“{}”的参数不能赋给类型“number”的参数。
  Overload 2 of 2, '(a: string): void', gave the following error.
    类型“{}”的参数不能赋给类型“string”的参数。ts(2769)
*/

它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。function reloadFunc(a): any 并不是重载列表的一部分,因此这里只有两个重载:一个是接受数字参数,一个是接受字符串参数,如果用别的方式调用就会报错

Updated: