📜  如何在 TypeScript 中声明模块?

📅  最后修改于: 2022-05-13 01:56:35.480000             🧑  作者: Mango

如何在 TypeScript 中声明模块?

模块是可以在另一个代码中调用或使用的一段代码。 Typescript 中的模块没有什么新东西。模块的概念是由 JavaScript 在 ECMAScript 2015 版本中引入的。 Typescript 只是重用了这个特性。

如果没有模块,代码会不会工作?

当然,它会的。代码仍然可以工作。但是没有模块化的代码有很大的缺点。

假设我们创建了一个非常基本的聊天应用程序,可以发送或接收文本消息。最初,我们仅在 2-3 个文件中添加了整个代码,并且应用程序运行良好。后来我们决定添加一个功能来录制和发送音频消息。为此,我们再次将更多代码添加到相同的文件中,并且应用程序仍然运行良好。后来我们决定添加共享图像或共享视频或一些大型文档等功能,我们继续将代码转储到相同的文件或 1 或 2 个额外文件中。现在有一个问题。以下是我们可以预见的几个问题:

  1. 我们的应用程序将开始变慢(或在某一时刻超级慢)。
  2. 应用程序频繁崩溃导致潜在的数据丢失
  3. 代码库将变成意大利面条(无法维护)
  4. 错误修复或调试是另一个大问题
  5. 测试团队的噩梦

如果我们只是使我们的代码更加模块化,那么上述所有问题(以及更多问题)都可以解决。

不使用模块的开发工作:让我们模拟一个场景。我们想买些水果。也许是苹果、猕猴桃和草莓。我们将为所有 3 个创建 3 个单独的类。由于所有 3 个都是水果,因此它们具有一些共同的特征,例如名称、颜色和数量。因此,我们将使用一种方法再创建一个类(作为一种数据类型)。让我们一个一个地创建类。

1. 创建 Apple 类:右键单击项目文件夹,然后单击“新建文件”。称之为apple.ts。首先,我们将在此处定义 Fruit 类用作苹果的数据类型,并且在同一个文件中,我们还将为 Apple 定义类:

Javascript
class Fruit {
 
  // Properties that every fruits have
  name: string;
  color: string;
  quantity: number;
 
  // To initialize the values
  constructor(name, color, quantity) {
      // Initialize values using this operator
  }
 
  myCart() {
     // A simple placeholder text
      console.log("I have " + this.quantity +
      " " + this.color + " " + this.name +
      " in my cart");
  }
}
 
class Apple {
  // Initialize Fruits class with values
  fruits: Fruits = new Fruits(..., ..., ...);
 
  constructor() {
  // call method to see everything is correct
      this.fruits.myCart();
  }
}
 
// initialize apple class and call
// its constructor automatically
var obj: Apple = new Apple();


Javascript
class Fruit {
 
  // Properties that every fruits have
  name: string;
  color: string;
  quantity: number;
 
  // Initialize the values
  constructor(name, color, quantity) {
 
      // Initialize values using this operator
  }
 
  myCart() {
 
     // A simple placeholder text
      console.log("I have " + this.quantity +
      " " + this.color + " " + this.name +
      " in my cart");
  }
}
 
class Kiwi {
 
  // Initialize Fruits class with values
  fruits: Fruits = new Fruits(..., ..., ...);
 
  constructor() {
 
  // Call method to see everything is correct
      this.fruits.myCart();
  }
}
 
// Initialize kiwi class and
// call its constructor automatically
var obj: Kiwi = new Kiwi();


Javascript
class Fruit {
 
  // Properties that every fruits have
  name: string;
  color: string;
  quantity: number;
 
  // Initialize the values
  constructor(name, color, quantity) {
 
      // Initialize values  using this operator
  }
 
  myCart() {
 
     // A simple placeholder text
      console.log("I have " + this.quantity +
      " " + this.color + " " + this.name +
      " in my cart");
  }
}
 
class Strawberry {
 
  // Initialize Fruits class with values
  fruits: Fruits = new Fruits(..., ..., ...);
   
  constructor() {
   
      // Call method to see everything is correct
      this.fruits.myCart();
  }
}
 
// Initialize strawberry class and
// call its constructor automatically
var obj: Strawberry = new Strawberry();


Javascript
export class Fruit {
 
  // Properties that every fruits have
  name: string;
  color: string;
  quantity: number;
 
  // Initialize the values
  constructor(name, color, quantity) {
 
      // Initialize values using this operator
  }
 
  myCart() {
 
     // A simple placeholder text
      console.log("I have " + this.quantity +
      " " + this.color + " " + this.name +
      " in my cart");
  }
}
 
console.log("Hello world!");


Javascript
import { Fruits } from './main';
 
class Apple {
  fruits: Fruits = new Fruits('apples', 'green', 5);
  constructor() {
      this.fruits.myCart();
  }
}
var obj: Apple = new Apple();


Javascript
import { Fruits } from './main';
class Kiwi {
  fruits: Fruits = new Fruits('kiwi', 'golden', 2);
  constructor() {
      this.fruits.myCart();
  }
}
var obj: Kiwi = new Kiwi();


Javascript
import { Fruits } from './main';
class Strawberry {
  fruits: Fruits = new Fruits('strawberries', 'red', 5);
  constructor() {
      this.fruits.myCart();
  }
}
var obj: Strawberry = new Strawberry();



我们将为 Kiwi 班做同样的程序

2. 创建 Kiwi 类:右键单击项目文件夹,然后单击“新建文件”。称之为kiwi.ts。首先,我们将在此处定义 Fruit 类用作 kiwi 的数据类型,在同一个文件中,我们还将为 Kiwi 定义类:

Javascript

class Fruit {
 
  // Properties that every fruits have
  name: string;
  color: string;
  quantity: number;
 
  // Initialize the values
  constructor(name, color, quantity) {
 
      // Initialize values using this operator
  }
 
  myCart() {
 
     // A simple placeholder text
      console.log("I have " + this.quantity +
      " " + this.color + " " + this.name +
      " in my cart");
  }
}
 
class Kiwi {
 
  // Initialize Fruits class with values
  fruits: Fruits = new Fruits(..., ..., ...);
 
  constructor() {
 
  // Call method to see everything is correct
      this.fruits.myCart();
  }
}
 
// Initialize kiwi class and
// call its constructor automatically
var obj: Kiwi = new Kiwi();


3. 创建草莓类:右键单击项目文件夹,然后单击“新建文件”。称之为草莓.ts。首先,我们将在此处定义 Fruit 类用作草莓的数据类型,在同一个文件中,我们还将为 Strawberry 定义类:

Javascript

class Fruit {
 
  // Properties that every fruits have
  name: string;
  color: string;
  quantity: number;
 
  // Initialize the values
  constructor(name, color, quantity) {
 
      // Initialize values  using this operator
  }
 
  myCart() {
 
     // A simple placeholder text
      console.log("I have " + this.quantity +
      " " + this.color + " " + this.name +
      " in my cart");
  }
}
 
class Strawberry {
 
  // Initialize Fruits class with values
  fruits: Fruits = new Fruits(..., ..., ...);
   
  constructor() {
   
      // Call method to see everything is correct
      this.fruits.myCart();
  }
}
 
// Initialize strawberry class and
// call its constructor automatically
var obj: Strawberry = new Strawberry();


使用模块化方法减少开发工作:上述方法存在一个重大缺陷。是的,你是对的。一次又一次地重新定义同一个 Fruits 类是非常愚蠢的。这就是模块出现的地方。如果我们将 Fruits 类保存在一个文件中并将其称为一个模块,然后在需要的地方调用该类/模块会怎样。这将为开发人员节省大量的时间和精力。让我们快点做吧。

第 1 步:创建一个名为 Fruits.ts 的新文件

第 2 步:从所有 3 个类中删除 Fruits 类定义

第 3 步:仅将其粘贴到一个位置,即文件Fruits.ts

Javascript

export class Fruit {
 
  // Properties that every fruits have
  name: string;
  color: string;
  quantity: number;
 
  // Initialize the values
  constructor(name, color, quantity) {
 
      // Initialize values using this operator
  }
 
  myCart() {
 
     // A simple placeholder text
      console.log("I have " + this.quantity +
      " " + this.color + " " + this.name +
      " in my cart");
  }
}
 
console.log("Hello world!");


请注意,我们首先使用了 export 关键字。 Export 关键字实际上使我们的类(或接口)可以在项目的其他地方使用。同时,我们在想要使用导出模块的模块中使用 Import 语句。

另请注意,我们在文件末尾添加了一条控制台日志语句。这不是必需的,但我们想在本文后面告诉您一个重要事实。现在,您可以忽略它并假设它不存在。

现在,当我们准备好我们的模块时。我们可以在课堂上调用它。从技术上讲,我们称之为“导入”,我们使用了一个名为“导入”的关键字。

句法:

import {classname} from './location';

让我们快速导入相同的内容:

文件名:Apple.ts

Javascript

import { Fruits } from './main';
 
class Apple {
  fruits: Fruits = new Fruits('apples', 'green', 5);
  constructor() {
      this.fruits.myCart();
  }
}
var obj: Apple = new Apple();


文件名:Kiwi.ts

Javascript

import { Fruits } from './main';
class Kiwi {
  fruits: Fruits = new Fruits('kiwi', 'golden', 2);
  constructor() {
      this.fruits.myCart();
  }
}
var obj: Kiwi = new Kiwi();


文件名:草莓.ts

Javascript

import { Fruits } from './main';
class Strawberry {
  fruits: Fruits = new Fruits('strawberries', 'red', 5);
  constructor() {
      this.fruits.myCart();
  }
}
var obj: Strawberry = new Strawberry();


看看它看起来有多干净。现在很容易理解和维护。这就是模块化方法背后的全部想法。

一些遗留问题:我们在最后添加了一个控制台语句。这是有原因的。让我先给你看一下输出。

输出

每次运行文件时,我们都会得到特定于类的输出,但也会得到“Hello world!”

原因是它不属于导出的类。那为什么叫它。原因是每当我们导入一个模块时,整个模块都会作为一个简单的程序执行一次,文件中的每一行都会被执行,无论它是否在导出类大括号内。所以要小心你放在那里的东西。在专家看来,不应该有杂散的代码行。以某种方法使用它们,或者在不需要时删除这些语句。

总结:因此,模块只不过是一种概念或方法,其中一段代码保持分离并显式导出,以便其他代码段可以导入它。我们使用 export 关键字使一个类公开可用,我们使用 import 来使用该导出的模块。

如何执行代码:

首先我们将运行:

tsc apple.ts

然后我们将运行:

node apple.js

之所以如此,是因为并非所有浏览器都像理解 JavaScript 那样理解 Typescript。所以 Typescript 首先必须被编译成 JavaScript,这就是我们使用 node 命令的原因。我们还可以使用 AND运算符将这两个命令组合在一起:

对于 Linux:

tsc apple.ts && node apple.js

对于 Windows,我可以使用管道运算符:

tsc apple.ts | node apple.js

同样,我可以运行 Kiwi 和 Strawberry 课程。

最终输出:

最后一点:

这是编写代码的专业方式,并被全球遵循。所以,明天如果你正在编写代码或审查别人的代码,请特别注意代码的模块化。这将使您的生活更轻松。