什么是 TypeScript 的 Module Augmentation

简介: 什么是 TypeScript 的 Module Augmentation

在进入模块扩充之前,让我们看看一些 TypeScript 合并原则,这些原则将随着我们的进步而变得有用。

TypeScript 支持创建完全同名的 class 和 interface:

class Food {
  cheese: string;
}
interface Food {
  bacon: string;
}
const food  = new Food();
food.bacon = "nice bacon";
food.cheese = "sweet cheese";
console.log(food); // {bacon: "nice bacon", cheese: "sweet cheese"}

在我们上面的例子中,我们可以看到,即使在 Food 类中只声明了 cheese,食物变量也包含 bacon 和 cheese。 这是因为,接口与类合并了。

但如果 interface 里包含的是方法,结果又如何?

class Food {
  cheese: string;
}
interface Food {
  bacon: string;
  bake(item: string);
}
const food  = new Food();
food.bake("cake"); // Error: food.bake is not a function

但是,bake 方法会在intelliSense 的帮助下显示在food 变量上,因为Food 类和接口Food 将合并,调用bake 方法会导致错误,因为接口只包含声明而不包含实现。 为了解决这个问题,我们可以将bake的实现添加到Food原型中。

Food.prototype.bake = (item) => console.log(item);

之后 bake 方法调用就能够工作了:

food.bake("cake"); // cake

模块扩充帮助我们将功能扩展到我们可能无法访问的第三方库或其他文件中的类

假设我们有一个带有 name 属性和 feed 方法的 Pet 类。

export class Pet {
  name: string;
  feed(feedType: string) {
    console.log(feedType);
  }
}

然后我们决定将这个类导入到我们的 index.ts 文件中,但不是只使用 Pet 类中的方法和属性,我们想要添加更多功能。 我们可以使用模块扩充来做到这一点。

首先,我们将 Pet 类导入到 index.ts 文件中。

import { Pet } from "./pet";

./pet 是一个模块。 为了扩展它,我们声明了一个使用相同名称的模块,在该模块中,我们将声明一个与我们尝试扩展的类同名的接口。 在接口中,我们将包含要添加到扩展类的属性和方法。

declare module "./pet" {
  interface Pet {
    age: number;
    walk(location: string);
  }
}

给 Pet 增添了一个 walk 方法的定义

TypeScript 将合并 Pet 类和 Pet 接口,因为它们可以在同一个 ./pet 模块中找到。

但这还不是全部。 记住我解释过,接口不包含方法的实现,而只包含它们的声明。 为此,我们将在 Pet 的原型中添加 walk 方法的实现。

Pet.prototype.walk = (location:string) => `Likes to walk in the ${location}`

现在我们可以调用 Pet 类中的方法和属性以及新声明的 Pet 接口。

const pet = new Pet();
pet.name = "Looty";
pet.age = 3;
pet.feed("bacon"); // bacon
console.log(pet.name = "Looty"); // Looty
console.log(pet.age = 3); // 3
console.log(pet.walk("park")); // Likes to walk in the park

现在你可能想知道,与其先通过 declare module 在增强后的 module 里声明一个接口,然后在 Pet 原型中添加 walk 方法的实现,为什么我们不直接声明一个同名的类,这样当类被初始化时,我们将拥有来自两者的方法?

答案是:TypeScript 不允许在类之间合并,所以我们不能创建两个或多个同名的类。

相关文章
|
12月前
|
JavaScript API
如何使用 TypeScript 的 module augmentation 技术增强 Spartacus Feature Library
如何使用 TypeScript 的 module augmentation 技术增强 Spartacus Feature Library
|
JavaScript 算法 编译器
TypeScript 里的 module 解析过程 - Module Resolution
TypeScript 里的 module 解析过程 - Module Resolution
243 0
|
JavaScript 前端开发 编译器
TypeScript 里的 module 概念
TypeScript 里的 module 概念
199 0
|
11天前
|
JavaScript
typeScript进阶(9)_type类型别名
本文介绍了TypeScript中类型别名的概念和用法。类型别名使用`type`关键字定义,可以为现有类型起一个新的名字,使代码更加清晰易懂。文章通过具体示例展示了如何定义类型别名以及如何在函数中使用类型别名。
27 1
typeScript进阶(9)_type类型别名
|
11天前
|
JavaScript
typeScript基础(2)_any任意值类型和类型推论
本文介绍了TypeScript中的`any`任意值类型,它可以赋值为其他任何类型。同时,文章还解释了TypeScript中的类型推论机制,即在没有明确指定类型时,TypeScript如何根据变量的初始赋值来推断其类型。如果变量初始化时未指定类型,将被推断为`any`类型,从而允许赋予任何类型的值。
28 4
|
11天前
|
JavaScript
typeScript基础(5)_对象的类型-interfaces接口
本文介绍了TypeScript中接口(interfaces)的基本概念和用法,包括如何定义接口、接口的简单使用、自定义属性、以及如何使用`readonly`关键字定义只读属性。接口在TypeScript中是定义对象形状的重要方式,可以规定对象的必有属性、可选属性、自定义属性和只读属性。
26 1
|
11天前
|
存储 JavaScript
typeScript进阶(11)_元组类型
本文介绍了TypeScript中的元组(Tuple)类型,它是一种特殊的数组类型,可以存储不同类型的元素。文章通过示例展示了如何声明元组类型以及如何给元组赋值。元组类型在定义时需要指定数组中每一项的类型,且在赋值时必须满足这些类型约束。此外,还探讨了如何给元组类型添加额外的元素,这些元素必须符合元组类型中定义的类型联合。
22 0
|
11天前
|
JavaScript
typeScript进阶(10)_字符串字面量类型
本文介绍了TypeScript中的字符串字面量类型,这种类型用来限制变量只能是某些特定的字符串字面量。通过使用`type`关键字声明,可以确保变量的值限定在预定义的字符串字面量集合中。文章通过示例代码展示了如何声明和使用字符串字面量类型,并说明了它在函数默认参数中的应用。
23 0
|
3月前
|
前端开发 JavaScript 安全
TypeScript在React Hooks中的应用:提升React开发的类型安全与可维护性
【7月更文挑战第17天】TypeScript在React Hooks中的应用极大地提升了React应用的类型安全性和可维护性。通过为状态、依赖项和自定义Hooks指定明确的类型,开发者可以编写更加健壮、易于理解和维护的代码。随着React和TypeScript的不断发展,结合两者的优势将成为构建现代Web应用的标准做法。
|
11天前
|
JavaScript 前端开发
typeScript基础(8)_ts类型断言
本文介绍了TypeScript中的类型断言,它用于在编译时告诉TypeScript某个对象具有特定的类型,即使它看起来不具备。类型断言可以用来访问一个类型上存在而另一个类型上不存在的属性或方法。需要注意的是,类型断言并不会在运行时改变JavaScript的行为,因此如果断言不当,运行时仍然可能出错。文章还提醒避免将类型断言为`any`类型或进行多重断言。
12 1