yaoningvital / blog

my blog
31 stars 4 forks source link

TypeScript -- Functions #184

Open yaoningvital opened 4 years ago

yaoningvital commented 4 years ago

原文地址:http://www.typescriptlang.org/docs/handbook/functions.html

一、给函数指定类型

如下面的示例:

function add(x: number, y: number): number {
    return x + y
}

let myAdd = function (x: number, y: number): number {
    return x + y
}

1、函数的参数必须要指定类型

如果没有指定,将报错:

function add(x, y: number):number {  // Error: TS7006: Parameter 'x' implicitly has an 'any' type.
    return x + y
}

image

2、函数的返回值的类型可以指定,也可以不指定。

因为TypeScript会根据函数参数的类型,去自动推断 return 后面的表达式的值的类型,所以函数的返回值的类型可以不指定。如下代码,TypeScript不会报错:

function add(x:number, y: number) {
    return x + y
}

3、指定函数类型的完整形式

指定一个函数类型的完整的形式如下:

let myAdd: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y
}

给变量 myAdd 赋值一个函数时,这个函数的参数的名字不必跟指定类型的函数的参数名称一致,只要类型一致即可。比如下面的赋值是OK的:

let myAdd: (baseValue: number, increment: number) => number = function (x: number, y: number): number {
    return x + y
}

4、函数的类型声明中只包含两部分:参数的类型、函数返回值的类型,不包含捕获变量的类型声明。

函数体重捕获的变量的类型不反映在类型中。实际上,捕获的变量是任何函数的“隐藏的状态”的一部分,不构成函数的API的一部分。

5、TypeScript可以推断类型

如下代码所示:

let myAdd: (baseValue: number, increment: number) => number = function (x, y) {
    return x + y
}

给myAdd指定了类型为一个函数,那么给它赋值一个函数,这个被赋值的函数的参数类型和返回值的类型就可以不指定,因为TypeScript会自动推断它们的类型。如下图所示,编辑器中显示的被赋值的函数的参数的类型就是TypeScript推断出来的: image

6、调用函数时,传给函数的参数个数 应该与 函数期待的参数个数 匹配

如果不匹配,TypeScript会报错:

function buildName(firstName: string, lastName: string) {
    return firstName + " " + lastName
}

buildName('yao') // Error TS2554: Expected 2 arguments, but got 1.  Example03.tsx(1, 39): An argument for 'lastName' was not provided.
buildName('yao','ning')
buildName('yao','xiao','ning') // Error TS2554: Expected 2 arguments, but got 3.

7、函数的可选参数(在参数名后标记?),可选参数必须放在必传参数的后面

function buildName(firstName: string, lastName?: string) {
    return firstName + " " + lastName
}

buildName('yao') 
buildName('yao','ning')
buildName('yao','xiao','ning') // Error TS2554: Expected 1-2 arguments, but got 3.

8、可以给函数的参数设置默认值

function buildName(firstName: string, lastName = 'smith') {
    return firstName + " " + lastName
}

buildName('yao')
buildName('yao', undefined)
buildName('yao', 'ning')
buildName('yao', 'xiao', 'ning') // Error TS2554: Expected 1-2 arguments, but got 3.

1、上例中,给参数 lastName 设置了默认值'smith'。如果 lastName 没接收到传值,或者接收到的值为 undefined ,那么 lastName 的值为 'smith'。 2、设置了默认值的参数可以不显示指定类型,TypeScript会根据默认值自动推断它的类型。比如上面的参数 lastName,TypeScript默认推断它为 string 类型: image

9、函数的参数可以使用扩展运算符(...)

function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(' ')
}

let buildNameFunc: (fName: string, ...rest: string[]) => string = buildName

10、函数中this的使用

函数中使用 this,没有指定它的类型,ts会报错。

let deck = {
    suits: ['hearts', 'spades', 'clubs', 'diamonds'],
    cards: Array(52),
    createCardPicker: function () {
        return function () {
            let pickedCard = Math.floor(Math.random() * 52)
            let pickedSuit = Math.floor(pickedCard / 13)
            return {
                suit: this.suits[pickedSuit],  // Error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.  Example03.tsx(5, 16): An outer value of 'this' is shadowed by this container.
                card: pickedCard % 13
            }
        }
    }
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()

console.log(`card:${pickedCard.card}, suit:${pickedCard.suit}`)

image

解决方案一:this所在的函数使用箭头函数,使this实际上指向deck对象

let deck = {
    suits: ['hearts', 'spades', 'clubs', 'diamonds'],
    cards: Array(52),
    createCardPicker: function () {
        return () => {
            let pickedCard = Math.floor(Math.random() * 52)
            let pickedSuit = Math.floor(pickedCard / 13)
            return {
                suit: this.suits[pickedSuit],
                card: pickedCard % 13
            }
        }
    }
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()

console.log(`card:${pickedCard.card}, suit:${pickedCard.suit}`)

解决方案二:将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),
    createCardPicker: function (this: Deck) {  // 显示将 this 传入函数,并且指定它的类型
        return () => {
            let pickedCard = Math.floor(Math.random() * 52)
            let pickedSuit = Math.floor(pickedCard / 13)
            return {
                suit: this.suits[pickedSuit],
                card: pickedCard % 13
            }
        }
    }
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()

console.log(`card:${pickedCard.card}, suit:${pickedCard.suit}`)