TypeScript 基础 函数类型

发布于 2025-01-26 05:42:24 字数 7470 浏览 18 评论 0

// 给每个参数添加类型之后再为函数本身添加返回值类型。 
// TypeScript 能够根据返回语句自动推断出返回值类型,因此我们通常省略它。
function add(x: number, y: number): number {
    return x + y;
}

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

完整函数类型

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

当写出完整函数类型的时候,这两部分都是需要的。 我们以参数列表的形式写出参数类型,为每个参数指定一个名字和类型。 这个名字只是为了增加可读性:

let myAdd: (x: number, y: number) => number =
    function(x: number, y: number): number { return x + y; };
// 也可以这么写,只要参数类型是匹配的,那么就认为它是有效的函数类型,而不在乎参数名是否正确。
let myAdd: (baseValue: number, increment: number) => number =
    function(x: number, y: number): number { return x + y; };

# 推断类型
// 如果在赋值语句的一边指定了类型但是另一边没有类型的话,TypeScript 编译器会自动识别出类型
let myAdd: (baseValue: number, increment: number) => number =
    function(x, y) { return x + y; };

对于返回值,我们在函数和返回值类型之前使用( => ) 符号,返回值类型是函数类型的必要部分,如果函数没有返回任何值,你也必须指定返回值类型为 void 而不能留空。

函数的类型只是由参数类型和返回值组成的。 函数中使用的捕获变量不会体现在类型里。 实际上,这些变量是函数的隐藏状态并不是组成 API 的一部分。

可选参数和默认参数

传递给一个函数的参数个数必须与函数期望的参数个数一致

JavaScript 里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是 undefined。 在 TypeScript 里我们可以在参数名旁 使用 ? 实现可选参数 的功能,但可选参数必须跟在必须参数后面

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

let result1 = buildName("Bob");  // works correctly now
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");  // ah, just right

默认值当用户 没有传递这个参数 或传递的 值是 undefined 时生效,如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined 值来获得默认值。

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

let result1 = buildName("Bob");                  // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");         // okay and returns "Bob Adams"
let result4 = buildName(undefined, "Adams");     // okay and returns "Will Adams"

剩余参数

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

let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

this

JavaScript 里, this 的值在函数被调用的时候才会指定。

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], card: pickedCard % 13};
        }
    }
}

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

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

上面的代码报错,因为 createCardPicker 返回的函数里的 this 被设置成了 window 而不是 deck 对象。因为我们只是独立的调用了 cardPicker() 。 顶级的非方法式调用会将 this 视为 window 。 (注意:在严格模式下, thisundefined 而不是 window )。

箭头函数能保存函数创建时的 this 值,而不是调用时的值

let deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    createCardPicker: function() {
        // 注意:下面的这条线现在是一个箭头函数,允许我们在这里捕捉 this
        return () => {
            let pickedCard = Math.floor(Math.random() * 52);
            let pickedSuit = Math.floor(pickedCard / 13);

            return {suit: this.suits[pickedSuit], card: pickedCard % 13};
        }
    }
}

如果你给编译器设置了 --noImplicitThis 标记。 它会指出 this.suits[pickedSuit] 里的 this 的类型为 any

this 参数

不幸的是, this.suits[pickedSuit] 的类型依旧为 any 。 这是因为 this 来自对象字面量里的函数表达式。 修改的方法是,提供一个显式的 this 参数。 this 参数是个假的参数,它出现在参数列表的最前面:

function f(this: void) {
    // 确保‘ this’在这个独立函数中不可用
}

让我们往例子里添加一些接口, CardDeck ,让类型重用能够变得清晰简单些:

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),
    // 注意: 这个函数现在明确指定它的被调用方必须是 Deck 类型
    createCardPicker: function(this: Deck) {
        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();

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

现在 TypeScript 知道 createCardPicker 期望在某个 Deck 对象上调用。 也就是说 thisDeck 类型的,而非 any ,因此 --noImplicitThis 不会报错了。

函数重载

重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。

如果参数类型不同,则参数类型应设置为 any 。参数数量不同你可以将不同的参数设置为可选。

根据传入不同的参数而返回不同类型的数据

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: {suit: string; card: number; }[]): number; // 参数为对象数组
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
    // 检查是否使用 object/array
    // 如果是这样,他们给我们一副牌,我们来选牌
    if (typeof x == "object") {
        let pickedCard = Math.floor(Math.random() * x.length);
        return pickedCard;
    }
    // 否则就让他们自己选牌
    else if (typeof x == "number") {
        let pickedSuit = Math.floor(x / 13);
        return { suit: suits[pickedSuit], card: x % 13 };
    }
}

let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

这样改变后,重载的 pickCard 函数在调用的时候会进行正确的类型检查。

为了让编译器能够选择正确的检查类型,它与 JavaScript 里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此, 在定义重载的时候,一定要把最精确的定义放在最前面

注意, function pickCard(x): any 并不是重载列表的一部分,因此这里只有两个重载:一个是接收对象另一个接收数字。 以其它参数调用 pickCard 会产生错误

小结

  1. 函数类型包含 参数类型返回值类型 两部分
  2. 传递给一个函数的参数个数必须与函数期望的参数个数一致
  3. 使用 ? 实现可选参数,可选参数必须跟在必须参数后面。
  4. 默认值当用户没有传递这个参数或传递的值是 undefined 时生效,如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined 值来获得默认值。
  5. JavaScript 里, this 的值在函数被调用的时候才会指定。而 箭头函数 能保存函数创建时的 this 值,而不是调用时的值
  6. 在定义重载的时候,一定要把最精确的定义放在最前面

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

雪落纷纷

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文