TypeScript 教程:概念、接口、枚举、数组及示例

什么是 TypeScript?

TypeScript 是 JavaScript 的超集。TypeScript 是一种纯面向对象的编程语言,支持类、接口等。它由 Microsoft 开发,是一种开源语言,可以将代码静态编译为 JavaScript。它可以轻松地在浏览器或 Nodejs 中运行。

TypeScript 支持 ECMAScript 发布的所有最新功能,此外,TypeScript 还拥有自己的面向对象功能,如接口、环境声明、类继承等,这有助于开发大型应用程序,而这在 JavaScript 中会很困难。

如何下载和安装 TypeScript

以下是下载和安装 TypeScript 的分步过程

步骤 1) 下载和安装 Nodejs

访问 Nodejs 官方网站:https://node.org.cn/en/download/,并根据您的操作系统下载和安装 Nodejs。有关如何下载 Nodejs 的详细说明,请访问:https://guru99.com.cn/download-install-node-js.html

步骤 2) 检查 Nodejs 和 npm 版本

要检查 nodejs 和 npm 是否已安装,只需在命令提示符中检查版本。

D:\typeproject>node --version
V10.15.1

D:\typeproject>npm --version
6.4.1

因此,您已安装 nodejs v10 和 npm 6。

步骤 3) TypeScript 安装

创建您的项目目录 typeproject/ 并运行 npm init,如下所示

npm init

步骤 4) 开始安装

现在,我们将创建 package.json,它将存储我们项目的依赖项。

完成后,按如下方式安装 TypeScript

npm -g install typescript

上述命令将负责安装 TypeScript。将“-g”添加到 npm install 将全局安装 TypeScript。使用 -g 的优点是您可以从任何目录使用 TypeScript tsc 命令,因为它已全局安装。如果您不想全局安装 TypeScript,请使用以下命令

npm --save install typescript

在项目目录中创建 src/ 文件夹,并在 src/ 文件夹中创建 TypeScript 文件 test.ts 并编写您的代码。

示例:test.ts

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

let sum = add(5,10);
console.log(sum);

将 TypeScript 代码编译为 JavaScript

要编译上述代码,请使用以下命令

如果 TypeScript 已全局安装,请使用以下命令

tsc test.ts

如果 TypeScript 已本地安装到您的项目中,您需要使用 node_modules 中的 TypeScript 路径,如下所示

node_modules/typescript/bin/tsc test.ts

上述命令将创建一个 test.js 文件,并将代码编译为 javascript。

示例:test.js

function add(x, y) {
    return x + y;
}
var sum = add(5, 10);
console.log(sum);

使用 Nodejs 执行 JavaScript

在本 TypeScript 教程中,我们将按如下方式在 Nodejs 中执行 test.js

D:\typeproject\src>node test.js
15

在执行 test.js 时,将显示控制台输出的值

在浏览器中执行 JavaScript

示例

<html>
<head></head>
<body>
<script type="text/javascript" src="test.js"></script>
</body>
</html>

Execute Javascript using Nodejs

使用 EcmaScript 版本将 TypeScript 代码编译为 JavaScript

TypeScript 支持所有已发布的 Ecmascript 功能,开发人员可以在编码时使用它们。但由于旧浏览器不支持所有新功能,因此您需要将 JavaScript 编译为旧版本的 Ecmascript。TypeScript 提供了可以执行此操作的编译器选项。

示例:test.ts

var addnumbers = (a, b) => {
    return a+b;
}

addnumbers(10, 20);

要编译为您选择的 ES 版本,您可以在命令中使用 target 或 t 选项,如下所示

tsc --target ES6  test.ts

OR

tsc -t ES6 test.ts

默认情况下,target 是 ES3。如果您想更改它,可以使用上述命令。

在此 TypeScript 教程中,我们将使用 ES6 作为目标

tsc --target ES6  test.ts

test.ts 到 test.js

var addnumbers = (a, b) => {
    return a+b;
}

addnumbers(10, 20);

代码保持不变,因为您使用的箭头函数是 ES6 功能,编译到 ES6 时,代码没有改变。

默认情况下,目标是 ES3,因此在没有 target 的情况下,您将获得 test.js,如下所示

var addnumbers = function (a, b) {
    return a + b;
};
addnumbers(10, 20);

因此,在这里,fat arrow 已更改为普通的匿名函数。

TypeScript 中的变量

变量用于存储值,值可以是字符串、数字、布尔值或表达式。在 TypeScript 中,变量与 JavaScript 类似。因此,让我们学习如何在 TypeScript 中声明和赋值变量。

变量在使用前必须定义。要声明变量,您可以使用

var 关键字,

let 关键字

const 关键字

在 TypeScript 中使用变量与 JavaScript 类似,熟悉 JavaScript 的用户会觉得它非常容易。与 var 相比,let const 等变量使用较少。

使用 var 声明变量

语法

var firstname = "Roy";

让我们看一些 TypeScript 示例来理解 var 关键字的工作原理以及使用 var 关键字声明的变量的作用域。

示例 1

var  k = 1; // variable k will have a global scope

function test() {
    var c = 1; // variable c is local variable and will be accessible inside function test, it will not be available outside the function.
    return k++;
}

test(); // output as  1
test(); // output as 2
alert(c); // will throw error , Uncaught ReferenceError: c is not defined

示例 2

var t = 0; // variable t is declared in global scope.
function test() {    
    var t = 10; //variable t is again redeclared inside function with value 10, so here t is local to the function and changes done to it will remain inside the function.
    return t;
}
test(); // will return 10.
console.log(t); // will console 0.

示例 3

var i = 0;
function test() {
    if (i>0) {
      var t = 1;
    }
    return t;
}

test(); // the value returned will be undefined. The if-block has the variable which gets executed when I> 0. Over here the if-block is not expected but you are still having a reference to the variable t, and it returns undefined, this is because var defined variables once defined inside a function will have reference to it inside the function.  
i++; // here value of i is incremented.
test(); // since i >0 the if block is executed and value returned is 1.

使用 let 声明变量

TypeScript 中 let 的语法如下

语法

let name="Roy";

let 变量的工作原理与 var 几乎相同,但有一个小的区别,我们将通过 TypeScript 示例来理解。

示例

let i = 1;
function test() {
    if (i>0) {
	  let t = 1;
    }
    return t;
}

test(); // throws an error : Uncaught ReferenceError: t is not defined.

上面的 TypeScript 示例会抛出错误,但如果使用 var 关键字,则相同的内容将正常工作。使用 let 声明的变量仅在声明的块作用域内可用,例如,变量 t 仅在 if-block 内可用,而不在整个函数中可用。

此外,如果您在任何函数、for 循环、while 循环、TypeScript switch 块中声明变量,它将仅在该块内可用,并且在块外部使用该变量时会引发错误。这是 var 和 let 关键字声明的变量之间的主要区别。

使用 const 声明变量

Const 意为常量变量。它们类似于 let 变量,唯一的区别是,一旦为其分配了值,就不能更改。

语法

const name;

示例

const age = "25"; 
age="30"; // will throw an error : Uncaught TypeError: Assignment to constant variable.

因此,用户只能在知道不需要更改分配给它的值的情况下使用 const 变量。

TypeScript 中的类型

TypeScript 是一种强类型语言,而 JavaScript 则不是。在 JavaScript 中,一个定义为字符串的变量可以轻松地更改为数字,而不会出现任何问题。TypeScript 不允许这样做。在 TypeScript 中,变量的类型在开始时就已定义,并且在整个执行过程中,它必须保持相同的类型,任何更改都会在编译到 JavaScript 时导致编译时错误。

以下是类型

  • 数字
  • 字符串
  • 布尔值
  • Any
  • Void

数字

仅接受整数、浮点数、分数等。

语法

let a :number = 10;
let marks :number = 150;
let price :number = 10.2;

以下是一些可用于 Number 类型的重要方法

toFixed() – 它会将数字转换为字符串,并保留传递给该方法的十进制位数。

toString() – 此方法将数字转换为字符串。

valueOf() – 此方法将返回数字的基本值。

toPrecision() – 此方法会将数字格式化为指定的长度。

示例:使用所有字符串方法

let _num :number = 10.345;
_num.toFixed(2); // "10.35"
_num.valueOf(); // 10.345
_num.toString(); // "10.345"
_num.toPrecision(2); //"10"

字符串

String:仅限字符串值

语法

let str :string = "hello world";

以下是一些可用于 String 类型的重要方法

  • split() – 此方法将字符串拆分为数组。
  • charAt() – 此方法将返回给定索引处的第一个字符。
  • indexOf() – 此方法将返回给定值的第一个出现位置。
  • Replace () – 此方法接受两个字符串,第一个是要在字符串中搜索的值,如果存在,则将其替换为第二个字符串,并返回一个新字符串。
  • Trim () – 此方法将删除字符串两侧的空格。
  • substr() – 此方法将返回字符串的一部分,该部分取决于给定的开始和结束位置。
  • substring() – 此方法将返回字符串的一部分,该部分取决于给定的开始和结束位置。结束位置处的字符将被排除。
  • toUpperCase() - 将字符串转换为大写
  • toLowerCase() – 将字符串转换为小写。

示例

let _str:string = "Typescript";

_str.charAt(1); // y
_str.split(""); //["T", "y", "p", "e", "s", "c", "r", "i", "p", "t"]
_str.indexOf("s"); //4 , gives -1 is the value does not exist in the string.
_str.replace("Type", "Coffee"); //"Coffeescript"
_str.trim(); //"Typescript"
_str.substr(4, _str.length); //"script"
_str.substring(4, 10); //"script"
_str.toUpperCase();//"TYPESCRIPT"
_str.toLowerCase();//"typescript"

布尔值

接受布尔值,如 true、false、0 和 1。

语法

let bflag :boolean = 1;
let status :boolean = true;

Any

语法

let a :any = 123
a = "hello world"; // changing type will not give any error.

使用 any 类型声明的变量可以接受字符串、数字、数组、布尔值或 void 类型的值。TypeScript 不会抛出任何编译时错误;这与 JavaScript 中声明的变量类似。仅在不确定将与该变量关联的值类型时使用 any 类型变量。

Void

Void 类型主要用作不返回任何内容的函数的返回类型。

语法

function testfunc():void{
 //code here
}

TypeScript 数组

TypeScript 中的数组是一种数据类型,您可以在其中存储多个值。让我们学习如何在 TypeScript 中声明和初始化数组以进行数组操作。

由于 TypeScript 是一种强类型语言,您必须告知数组中值的数据类型。否则,它将被视为 any 类型。

声明和初始化数组

语法

let nameofthearray : Array<typehere>

示例

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]; //array with all string values.

let years: Array<number> = [2015, 2016, 2017, 2018, 2019]; //array will all numbers

let month_year: Array<string | number> = ["Jan", 2015, "Feb", 2016]; //array with string and numbers mixed.

let alltypes: Array<any> = [true, false, "Harry", 2000, { "a": "50", "b": "20" }]; //array of all types boolean, string , number , object etc.

访问数组元素的各种方法

要从数组中获取元素,值从索引 0 开始,直到数组的长度。

示例

let years: Array<number> = [ 2016, 2017, 2018, 2019]; //array will all numbers			
years[0]; // output will be 2016			
years[1]; // output will be 2017			
years[2]; // output will be 2018			
years[3]; // output will be 2019

您也可以使用 TypeScript 中的循环来访问数组元素,如下所示

使用 TypeScript for 循环

let years: Array<number> = [ 2016, 2017, 2018, 2019]; 
for (let i=0;i<=years.length; i++) {
     console.log(years[i]);
}
Output:
2016
2017
2018
2019

使用 for-in 循环

let years: Array<number> = [ 2016, 2017, 2018, 2019]; 
for (let i in years) {
     console.log(years[i])
}

Output:
2016
2017
2018
2019

使用 for-of 循环

let years: Array<number> = [ 2016, 2017, 2018, 2019]; 
for (let  i of years) {
     console.log(i)
}
Output:
2016
2017
2018
2019

使用 foreach 循环

let years: Array<number> = [ 2016, 2017, 2018, 2019]; 
years.forEach(function(yrs, i) {
  console.log(yrs);
});
Output:
2016
2017
2018
2019

TypeScript 数组方法

TypeScript 数组对象具有许多属性和方法,可以帮助开发人员轻松高效地处理数组。您可以通过指定 arrayname.property 来获取属性的值,并通过指定 array name.method() 来获取方法的输出。

length 属性

=> 如果您想知道数组中元素的数量,可以使用 length 属性。

reverse 方法

=> 您可以使用 reverse 方法反转数组中项目的顺序。

sort 方法

=> 您可以使用 sort 方法对数组中的项目进行排序。

pop 方法

=> 您可以使用 pop 方法删除数组的最后一个项目。

shift 方法

=> 您可以使用 shift 方法删除数组的第一个项目。

push 方法

=> 您可以将值添加为数组的最后一个项目。

concat 方法

=> 您可以将两个数组连接成一个数组元素。

length 属性示例

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]; //array with all string values.

console.log(months.length);  // 12

reverse 方法示例

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]; //array with all string values.

console.log(months.reverse());  //  ["Dec", "Nov", "Oct", "Sept", "Aug", "July", "June", "May", "April", "March", "Feb", "Jan"]

sort 方法示例

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]; //array with all string values.

console.log(months.sort()); // ["April", "Aug", "Dec", "Feb", "Jan", "July", "June", "March", "May", "Nov", "Oct", "Sept"]

pop 方法示例

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]; //array with all string values.				

console.log(months.pop()); //Dec

shift 方法示例

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]; //array with all string values.			

console.log(months.shift()); // Jan

push 方法示例

let years: Array<number> = [2015, 2016, 2017, 2018, 2019]; //array will all numbers			
console.log(years.push(2020)); 			
years.forEach(function(yrs, i) {			
  console.log(yrs); // 2015 , 2016,2017, 2018, 2019,2020				
});

concat 方法示例

let array1: Array<number> = [10, 20, 30]; 			
let array2: Array<number> = [100, 200, 300];			
console.log(array1.concat(array2)); //[10, 20, 30, 100, 200, 300]

TypeScript 中的类

TypeScript 是 JavaScript 的超集,因此在 JavaScript 中可以做到的事情在 TypeScript 中也可以做到。Class 是从 ES6 开始添加的一项新功能,因此早期在 JavaScript 中,类类型功能是通过带有原型功能的函数来实现代码重用。使用类,您可以使您的代码几乎接近 Java、C#、Python 等语言,在这些语言中代码可以重用。借助 TypeScript/JavaScript 中的类功能,该语言变得非常强大。

在 TypeScript 中定义类

这是 TypeScript 中的基本类语法

class nameofclass {
     //define your properties here

    constructor() {
     // initialize your properties here
    }
 
   //define methods for class
}

示例:一个关于类的有效示例

class Students {
    age : number;
    name : string;
    roll_no : number;
    
    constructor(age: number, name:string, roll_no: number) {
        this.age = age;
        this.name = name;
        this.roll_no = roll_no;
    }

    getRollNo(): number {
        return this.roll_no;
    }

    getName() : string {
        return this.name;
    }

    getAge() : number {
        return this.age;
    }
}

在上面的示例中,您有一个名为 Students 的类。它具有 age、name 和 roll_no 属性。

TypeScript 类中的构造函数

我们上面定义的 Students 类示例,它有一个构造函数,如下所示

constructor(age: number, name:string, roll_no: number) {
        this.age = age;
        this.name = name;
        this.roll_no = roll_no;
    }

构造函数方法有 age、name 和 roll_no 参数。构造函数将在调用类时负责初始化属性。属性使用 this 关键字访问。例如 this.age 访问 age 属性,this.roll_no 访问 roll_no 等。您还可以有一个默认构造函数,如下所示

constructor () {}

TypeScript 类中的方法

Students 类示例中有定义的方法,例如 getRollNo()、getName()、getAge(),它们用于提供 roll_no、name 和 age 属性的详细信息。

getRollNo(): number {
        return this.roll_no;
}

getName() : string {
	return this.name;
}

getAge() : number {
	return this.age;
}

在 TypeScript 中创建类实例

示例

在 TypeScript 中创建类实例需要使用 new 运算符。当我们使用 new 运算符创建类实例时,我们得到一个对象,该对象可以访问类的属性和方法,如下所示

let student_details = new Students(15, "Harry John", 33);
student_details.getAge(); // 15
student_details.getName(); // Harry John

将 TypeScript 类编译为 JavaScript

您可以使用 tsc 命令,如下所示进行编译为 Javascript。

Command: tsc  Students.ts

编译后的 Javascript 代码如下所示

var Students = /** @class */ (function () {
    function Students(age, name, roll_no) {
        this.age = age;
        this.name = name;
        this.roll_no = roll_no;
    }
    Students.prototype.getRollNo = function () {
        return this.roll_no;
    };
    Students.prototype.getName = function () {
        return this.name;
    };
    Students.prototype.getAge = function () {
        return this.age;
    };
    return Students;
}());

在 JavaScript 中,类被转换为自调用函数。

类继承

类可以使用 TypeScript 中的 extend 关键字进行继承。

类继承语法

class A {
     //define your properties here

    constructor() {
     // initialize your properties here
    }
 
   //define methods for class

}

class B extends A {
 //define your properties here

    constructor() {
     // initialize your properties here
    }
 
   //define methods for class

}

class B 将能够共享 class A 的方法和属性。

这是一个使用继承的类的有效示例

class Person {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    getName(): string {
        return this.name;
    }

    getAge(): number {
        return this.age;
    }
}

class Student extends Person {
    tmarks: number;
    getMarks(): number {
        return this.tmarks;
    }

    setMarks(tmarks) {
        this.tmarks = tmarks;
    }
}

let _std1 = new Student('Sheena', 24);
_std1.getAge(); // output is 24
_std1.setMarks(500);
_std1.getMarks(); // output is 500

您有两个类,Person 和 Student。Student 类扩展了 Person,并且在 Student 上创建的对象能够访问其自身的方法和属性以及它所扩展的类。

现在让我们对上面的类进行一些更改。

示例

class Person {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    getName(): string {
        return this.name;
    }

    getAge(): number {
        return this.age;
    }
}

class Student extends Person {
    tmarks: number;
    constructor(name: string, age: number, tmarks: number) {
        super(name, age);
    }
    getMarks(): number {
        return this.tmarks;
    }

    setMarks(tmarks) {
        this.tmarks = tmarks;
    }
}

let _std1 = new Student('Sheena', 24, 500);
_std1.getAge(); // output is 24
_std1.getMarks(); // output is 500

与前一个示例相比,您添加的更改是在 Student 类中定义了构造函数。构造函数必须接受与基类相同的参数,并根据需要添加其自身的任何附加参数。

在 TypeScript 中,您需要在构造函数中调用 super 并传递所有基类参数。这必须是构造函数内部要执行的第一件事。super 将执行扩展类的构造函数。

TypeScript 中的访问修饰符

TypeScript 支持类的方法和属性的 public、private 和 protected 访问修饰符。默认情况下,如果未提供访问修饰符,则该方法或属性被视为 public,并且可以从类的对象轻松访问。

在 private 访问修饰符的情况下,它们不能从类的对象访问,并且只能在类内部使用。它们不能用于继承的类。

在 protected 访问修饰符的情况下,它们仅用于类内部和继承的类,不能从类的对象访问。

示例

class Person {
    protected name: string;
    protected age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    private getName(): string {
        return this.name;
    }

    getDetails(): string {
        return "Name is "+ this.getName();
    }
}

class Student extends Person {
    tmarks: number;
    constructor(name: string, age: number, tmarks: number) {
        super(name, age);  
        this.tmarks = tmarks;    
    }
    getMarks(): number {
        return this.tmarks;
    }

    getFullName(): string {
        return this.name;
    }
    
    setMarks(tmarks) {
        this.tmarks = tmarks;
    }
}

let _std1 = new Student('Sheena', 24, 500);
_std1.getMarks(); // output is 500
_std1.getFullName(); // output is Sheena
_std1.getDetails(); // output is Name is Sheena
  • Private:属性或方法不能被类的对象以及派生类访问,它们仅用于类内部。
  • Protected:属性和方法也不能被创建的对象访问。它们可以在类内部访问,并且可供扩展它的类使用。
  • Public:属性和方法在没有关键字的情况下声明。它们可以使用类的对象从外部轻松访问。

TypeScript 中的接口

TypeScript 的核心功能之一是接口。接口是一组规则定义,需要由使用它的实体实现。实体可以是类、函数或变量。接口可以由属性和方法组成。您可以使用属性或方法前的“?”语法将属性定义为可选。接口为实现接口的任何函数、变量或类添加了强类型检查。

TypeScript 中接口的语法

interface Dimension {
    width: string;
    height: string;
}

您已定义了一个名为 Dimension 的接口,它具有 width 和 height 属性,两者都具有字符串类型。

现在,此接口可以由变量、函数或类实现。以下是实现 Dimension 接口的变量的示例。

示例

interface Dimension {
    width: string;
    height: string;
}

let _imagedim: Dimension = {
    width: "100px",
    height: "200px"
};

接口 Dimension 的签名具有 width 和 height,两者都是必需的。如果实现接口时,任何属性丢失,或类型更改,在编译代码为 javascript 时都会导致编译时错误。

上面的代码编译为 javascript 后如下所示

var _imagedim = {
    width: "100px",
    height: "200px"
};

现在让我们看看如何将接口与函数一起使用。

将接口用作函数的返回类型

示例

interface Dimension {
    width: string;
    height: string;
}

function getDimension() : Dimension {
    let width = "300px";
    let height = "250px";
    return {
        width: width,
        height: height
    }
}

在上面的示例中,接口 Dimension 已作为返回类型应用于 getDimension() 函数。getDimension() 的返回类型必须与接口 Dimension 所指定的属性和类型匹配。

编译为 Javascript 的代码如下所示

function getDimension() {
    var width = "300px";
    var height = "250px";
    return {
        width: width,
        height: height
    };
}

在编译过程中,如果返回类型与接口不匹配,它将引发错误。

接口作为函数参数

interface Dimension {
    width: string;
    height: string;
}

function getDimension(dim: Dimension) : string {
    let finaldim  = dim.width +"-"+ dim.height;
    return finaldim;
}

getDimension({width:"300px", height:"250px"}); // will get "300px-250px"

所以上面的例子中,您已经使用接口 Dimension 作为 getDimension() 函数的参数。当您调用该函数时,您需要确保传递给它的参数与定义的接口规则匹配。

编译为 Javascript 的代码如下所示

function getDimension(dim) {
    var finaldim = dim.width + "-" + dim.height;
    return finaldim;
}
getDimension({ width: "300px", height: "250px" });

实现接口的类

要使接口与类一起使用,您需要使用 implements 关键字。

实现接口的类的语法

class NameofClass implements InterfaceName {
}

以下示例展示了接口与类的用法。

interface Dimension {
    width : string,
    height: string,
    getWidth(): string; 
}

class Shapes implements Dimension {
    width: string;
    height: string;
    constructor (width:string, height:string) {
        this.width = width;
        this.height = height;
    }
    getWidth() {
        return this.width;
    }
}

在上面的示例中,您已定义了接口 Dimension,它具有 string 类型的 width 和 height 属性,以及一个名为 getWidth() 的方法,该方法的返回值为 string。

编译为 Javascript 的代码如下所示

var Shapes = /** @class */ (function () {
    function Shapes(width, height) {
        this.width = width;
        this.height = height;
    }
    Shapes.prototype.getWidth = function () {
        return this.width;
    };
    return Shapes;
}());

TypeScript 中的函数

函数是一组用于执行任务的指令。在 JavaScript 中,大部分代码都是以函数的形式编写的,并且起着重要作用。在 TypeScript 中,您拥有类、接口、模块、命名空间,但函数仍然起着重要作用。JavaScript 和 TypeScript 函数之间的区别在于 TypeScript 函数具有的返回类型。

JavaScript 函数

function add (a1, b1) { 
   return a1+b1;
}

TypeScript 函数

function  add(a1 : number, b1: number) : number {
    return a1 + b1;
}

在上面的函数中,添加了函数名,参数是 a1b1,两者都是 number 类型,返回类型也是 number。如果您向函数传递字符串,在编译为 JavaScript 时它将引发编译时错误。

调用函数:add

let  x = add(5, 10) ;  // will return 15
let  b = add(5); // will throw an error : error TS2554: Expected 2 arguments, but got 1.
let c = add(3,4,5); // will throw an error : error TS2554: Expected 2 arguments, but got 3.
let t = add("Harry", "John");// will throw an error :  error TS2345: Argument of type '"Harry"' is not assignable to parameter of type 'number'.

参数 a1b1 是必需参数,如果未按此方式接收,则会引发错误。此外,参数类型和返回类型非常重要,一旦定义就不能更改。

为函数设置可选参数

在 JavaScript 中,函数的所有参数都是可选的,如果未传递,则被视为 undefined。但 TypeScript 不是这样,一旦定义了参数,您就需要传递它们,但如果您想让任何参数可选,您可以使用?放在参数名之前,如下所示

function getName(firstname: string, lastname?: string): string {
    return firstname + lastname;
}

let a = getName("John"); // will return Johnundefined.
let b = getName("John", "Harry"); // will return JohnHarry
let c = getName("John", "H", "Harry"); // error TS2554: Expected 1-2 arguments, but got 3.

请注意,可选参数必须定义在函数的最后,您不能将第一个参数设为可选而第二个参数设为必需。当您使用一个参数调用函数时,编译器会引发错误。因此,有必要将可选参数放在最后。

为参数设置默认值

您可以通过如下方式为参数设置默认值

function getName(firstname: string, lastname = "Harry"): string {
    return firstname + lastname;
}

let a = getName("John"); // will return JohnHarry
let b = getName("John", "H"); // will return JohnH

与可选参数类似,这里默认初始化的参数也必须放在函数末尾。

Rest 参数

您已经看到了 TypeScript 如何处理必需参数、可选参数和默认值初始化的参数。现在,我们将看一下 rest 参数。Rest 参数是一组一起定义的可选参数,它们使用三个 点 (…) 后跟参数名(一个数组)来定义。

Rest 参数的语法

function testFunc(a: string, ...arr: string[]) :string {
    return a + arr.join("");
}

如上所示,rest 参数使用 (…param-name) 定义;rest 参数是一个由三个点前缀的数组。该数组将包含传递给它的所有参数。您可以按如下示例调用函数

示例

let a = testFunc("Monday", "Tuesday", "Wednesday", "Thursday"); // will get output as MondayTuesdayWednesdayThursday

箭头函数

箭头函数是 ES6 中发布的重要功能之一,它在 TypeScript 中也可用。箭头函数的语法包含一个 fat arrow,因此该函数被称为箭头函数。

箭头函数语法

var nameoffunction = (params) => {				
 // code here			
}

箭头函数的用途是什么?

让我们看一个示例来理解箭头函数的用例

示例

var ScoreCard = function () {
    this.score = 0;

    this.getScore = function () {
        setTimeout(function () {
            console.log(this.score);    // gives undefined.    
        }, 1000);
    }    
}

var a = new ScoreCard();
a.getScore();

您创建了一个匿名函数,该函数具有属性 this.Score 初始化为 0 和一个 getScore 方法,该方法内部有一个 setTimeout,1 秒后它会 console.log this.score。console.log 的值是 undefined,即使您定义并初始化了 this.score。问题在于 this 关键字。setTimeout 内的函数有自己的 this,它试图在内部引用 score,由于它未定义,因此返回 undefined。

如下所示,可以使用箭头函数解决同样的问题

var ScoreCard = function () {
    this.score = 0;

    this.getScore = function () {
        setTimeout(()=>{
            console.log(this.score);   // you get  0
        }, 1000);
    }    
}

var a = new ScoreCard();
a.getScore();

您已将 setTimeout 内的函数更改为箭头函数,如下所示

setTimeout(()=>{
            console.log(this.score);   // you get  0
        }, 1000);

箭头函数没有自己的 this 定义,它共享其父级的 this,因此在箭头函数内部可以轻松访问外部声明的变量。它们因为语法更短,并且适用于回调、事件处理程序、定时函数等。

TypeScript 枚举

TypeScript Enum 是一个对象,其中包含一组相关的已存储值。JavaScript 不支持枚举。大多数 编程语言,如 Java、C、C++,都支持 TypeScript Enum,TypeScript 也支持。Enum 使用 enum 关键字定义。

如何声明 Enum?

语法

enum NameofEnum {
   value1,
   value2,
    ..
}

示例:Enum

enum Directions {
North,
South,
East,
West
}

在上面的示例中,您定义了一个名为 Directions 的枚举。给定值是 North、South、East、West。值从枚举的第一个值 0 开始编号,然后依次递增 1。

声明一个数字枚举

默认情况下,如果枚举没有给定任何值,它将视为从 0 开始的数字。以下示例显示了一个数字枚举。

enum Directions {
North = 0,
South = 1, 
East =2,
West =3
}

您还可以为枚举分配一个起始值,下一个枚举值将获得递增的值。例如

enum Directions {
North = 5,
South, // will be 6
East, // 7
West // 8
}

现在枚举值 North 从 5 开始,所以 South 的值为 6,East = 7,West = 8。

您也可以分配您选择的值,而不是使用默认值。例如

enum Directions {
North = 5,
South = 4,
East = 6,
West = 8
}

如何访问 Enum?

以下示例显示了如何在代码中使用 Enum

enum Directions {
    North,
    South,
    East,
    West
}

console.log(Directions.North); // output is  0
console.log(Directions["North"]); // output is 0
console.log(Directions[0]); //output is North

编译为 Javascript 的代码如下所示

var Directions;
(function (Directions) {
    Directions[Directions["North"] = 0] = "North";
    Directions[Directions["South"] = 1] = "South";
    Directions[Directions["East"] = 2] = "East";
    Directions[Directions["West"] = 3] = "West";
})(Directions || (Directions = {}));
console.log(Directions.North);
console.log(Directions["North"]);
console.log(Directions[0]);

由于 JavaScript 不支持枚举,它会将枚举转换为自调用函数,如上所示。

声明一个字符串枚举

您可以分配您选择的字符串值,如以下示例所示

示例

enum Directions {
    North = "N",
    South = "S",
    East = "E",
    West = "W"
}

console.log(Directions.North); // output is N
console.log(Directions["North"]); // output is N
console.log(Directions[0]); // output is North

编译为 Javascript 的代码如下所示

var Directions;
(function (Directions) {
    Directions["North"] = "N";
    Directions["South"] = "S";
    Directions["East"] = "E";
    Directions["West"] = "W";
})(Directions || (Directions = {}));
console.log(Directions.North);
console.log(Directions["North"]);
console.log(Directions[0]);

TypeScript 中的模块是什么?

在 TypeScript 中创建的文件具有全局访问权限,这意味着在一个文件中声明的变量可以轻松地在另一个文件中访问。这种全局性质可能导致代码冲突,并在运行时导致执行问题。您可以使用 export 和 import 模块功能来避免全局变量、函数冲突。此功能在 ES6 发布的 JavaScript 中可用,并且在 TypeScript 中也受支持。

为什么需要 TypeScript 中的模块?

以下示例显示了没有模块的问题

示例 test1.ts

let age : number = 25;

您在 test1.ts 中定义了一个 number 类型的变量 age。

示例 test2.ts

在 test2.ts 文件中,您可以轻松访问 test1.ts 中定义的变量 age,还可以按如下方式修改它

age = 30; // changed from 25 to 30.
let _new_age = age;

因此,上述情况可能会导致许多问题,因为变量是全局可用的并且可以被修改。

使用 Modules,编写的代码仅限于文件本身,不能在文件外部访问。要从文件中访问任何内容,必须使用 export 关键字导出。当您希望变量、类、函数或接口在另一个文件中使用时,就会使用 export。当您想访问导出的变量、类、接口或函数时,就会使用 import。这样做可以使代码保留在文件内部,即使您定义了相同的变量名,它们也不会混淆,并且在声明它们的文件中表现为局部变量。

使用 Export 和 Import

有多种导出和导入方式。所以我们将讨论这里最常用的语法。

import 和 export 1 的语法

export  nameofthevariable or class name or interface name etc

//To import above variable or class name or interface you have to use import as shown below:
 

Import {nameof thevariable or class name or interfacename} from "file path here without.ts"

这是一个使用 export 和 import 的有效示例。

示例

test1.ts

export let age: number = 25;

Export 关键字用于在另一个文件中共享 age 变量。

test2.ts

import { age } from "./test1"
let new_age :number = age;

Import 关键字用于访问 age 变量,您需要指定文件位置,如上所示。

import 和 export 2 的语法

还有另一种导出和导入方式,其语法如下所示

export = classname;

import classname = require(“file path of modulename”)

当您使用 export = 导出模块时,导入必须使用 require(“module name 的文件路径”) 来导入它。

这是一个展示上述情况的有效示例

Customer.ts

class Customer {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    getName(): string {
        return this.name;
    }
}

export = Customer;

testCustomer.ts

import Customer = require("./Customer");

let a = new Customer("Harry", 30);
alert(a.getName());

模块加载器

模块不能独立工作,因此您需要模块加载器来定位导入的依赖项,如您在上面看到的 TypeScript 示例所示。可用的模块加载器是 CommonJS(用于 nodejs)和 Require.js(用于在浏览器中运行)。

要使用 CommonJS 模块编译代码,请使用以下命令

tsc --module commonjs testCustomer.ts

要使用 Requirejs 模块编译代码,请使用以下命令

tsc --module amd testCustomer.ts

依赖文件将使用上述命令转换为 js 文件。

使用 Requirejs 将 testCustomer.ts 示例编译为 testCustomer.js

define(["require", "exports", "./Customer"], function (require, exports, Customer) {
    "use strict";
    exports.__esModule = true;
    var a = new Customer("Harry", 30);
    alert(a.getName());
});

使用 Requirejs 将 Customer.ts 示例编译为 Customer.js

define(["require", "exports"], function (require, exports) {
    "use strict";
    var Customer = /** @class */ (function () {
        function Customer(name, age) {
            this.name = name;
            this.age = age;
        }
        Customer.prototype.getName = function () {
            return this.name;
        };
        return Customer;
    }());
    return Customer;
});

要使用 require.js 测试它,您需要创建一个名为 main.js 的文件,该文件包含对依赖项的引用,如下所示。

文件夹结构如下

src/
    Customer.js
    testCustomer.js
    main.js
    require.js  // you can get this file from github or npm install requirejs
    test.html

main.js

define(function (require) {
    var customer = require("./Customer");
    var testCustomer = require("./testCustomer");
});

test.html

<!DOCTYPE html>			
<html>			
<head>			
    <title>TypeScript Module testing using Requirejs</title>			
    <script data-main="main" src="require.js"></script>			
</head>			
<body>			
    <h3>Testing modules using Requirejs</h3>			
</body>			
</html>

Module Loader

TypeScript 中的命名空间

命名空间基本上是在一个文件中集合了类、接口、变量、函数。

命名空间语法

namespace name{

export class {
}

export interface {
}

export const constname;

}

代码都在一个命名空间下。

命名空间工作示例:testnamespace.ts

namespace StudentSetup {

    export interface StudDetails {
        name: string;
        age: number;
    }

    export function addSpace(str) { // will add space to the string given
        return str.split("").join(" ");
    }

    export class Student implements StudDetails {
        name: string;
        age: number;

        constructor(studentdetails: StudDetails) {
            this.name = studentdetails.name;
            this.age = studentdetails.age;
        }

        getName(): string {
            return this.name;
        }
    }
}

命名空间的名称是 StudentSetup,您添加了一个接口 StudDetails、一个函数 addSpace 和一个名为 Student 的类。

访问命名空间

以下代码展示了如何使用命名空间 StudentSetup

testStudentSetup.ts

let a = new StudentSetup.Student({ name: "Harry", age: 20 });

console.log("The name is :" + StudentSetup.addSpace(a.getName()));

命名空间内可用的类、接口、函数必须使用命名空间名称引用,例如 StudentSetup.addSpace 来访问函数,StudentSetup.Student 来访问类。

您可以将这两个文件编译成一个 js 文件,如下所示

tsc --outFile namespace.js testnamespace.ts  testStudentSetup.ts

使用以下命令在命令提示符中查看输出

node namespace.js

它将显示如下输出

The name is: H a r r y

TypeScript 中的环境声明

TypeScript 允许您使用环境声明来使用第三方 JavaScript 文件。此功能的好处是您不必重写即可使用库的所有功能。

环境语法

声明环境模块

declare module moduleName {
   //code here
}

环境文件必须保存为

filename.d.ts

要在您的 .ts 文件中使用 filename.d.ts 文件,您需要像这样引用它

/// <reference path="filename.d.ts"/>

TypeScript 中的环境类型声明将引用第三方库,并用自己的类型重新声明所需的函数。例如,考虑您有一个小型 JavaScript 库,如下所示

第三方 JavaScript 文件:testString.js

示例:testString.js

var StringChecks = {
    isString: function (str) {
        return typeof str === "string";
    },

    convertToUpperCase: function (str) {
        return str.toUpperCase();
    },

    convertToLowerCase: function (str) {
        return str.toLowerCase();
    },

    convertToStringBold: function (str) {
        return str.bold();
    }
};

您有一个名为 StringChecks 的对象,它具有 isString、convertToUpperCase、convertToLowerCase 和 converToStringBold 等函数。

在 TypeScript 中创建环境模块

现在我们将创建一个环境模块,它将引用上面的 js 函数,并根据我们的需求添加类型检查。

文件名:tstring.d.ts

declare module TestString {

    export interface StringsFunc {
        isString(str: string): boolean;
        convertToUpperCase(str: string): string;
        convertToLowerCase(str: string): string;
        convertToStringBold(str: string): string;
    }
}

declare var StringChecks: TestString.StringsFunc;

您必须将模块名称定义为 TestString,并导出接口 StringsFunc。

isString(str: string): boolean

=> 这将接受字符串作为参数,返回类型为布尔值。在 .ts 文件中使用时,如果您传递的参数是数字或其他非字符串类型,它将为您提供编译时错误。

convertToUpperCase(str:string): string

=> 这将接受字符串作为参数并返回一个字符串。convertToLowerCase(str: string) 也是如此
: string; 和 convertToStringBold(str: string): string
;

由于 JavaScript 文件中的对象名为 StringChecks,最终我们需要在 .d.ts 文件中引用它,这可以通过以下方式完成

declare var StringChecks: TestString.StringsFunc;

在 TypeScript 中使用环境模块

现在,这是我们将使用环境文件 tstring.d.ts 的 test.ts 文件

示例:test.ts

/// <reference path="tstring.d.ts"/>
let str1 = StringChecks.isString("Hello World");
console.log(str1);
let str2 = StringChecks.convertToUpperCase("hello world");
console.log(str2);
let str3 = StringChecks.convertToLowerCase("HELLO");
console.log(str3);
let str4 = StringChecks.convertToStringBold("Hello World");
console.log(str4);

将 TypeScript tsc test.ts 编译为 test.js

/// <reference path="tstring.d.ts"/>
var str1 = StringChecks.isString("Hello World");
console.log(str1);
var str2 = StringChecks.convertToUpperCase("hello world");
console.log(str2);
var str3 = StringChecks.convertToLowerCase("HELLO");
console.log(str3);
var str4 = StringChecks.convertToStringBold("Hello World");
console.log(str4);

现在您可以在 html 文件中使用 test.js 以及库文件 testString.js

<html>			
<head>			
    <title>Test TypeScript Ambient</title>			
    <script src="testStrings.js"></script>			
    <script src="test.js"></script>			
</head>			
<body>			
</body>			
</html>

这是控制台中看到的输出

true			
HELLO WORLD			
hello			
<b>Hello World</b>

TypeScript 历史

让我们看看 TypeScript 历史上的重要里程碑

  • 经过 Microsoft 两年多的内部开发。TypeScript 0.9,于 2013 年发布
  • 2013 年 Build 大会发布了对泛型 TypeScript 1.0 的额外支持
  • 2014 年 7 月,新的 TypeScript 编译器发布,其速度是前版本的五倍。
  • 2015 年 7 月,增加了对 ES6 模块、namespace 关键字、for、of 支持、decorators 的支持。
  • 2016 年 11 月,增加了如 key 和 lookup types 的映射类型以及 rest 等功能。
  • 2018 年 3 月 27 日,TypeScript 中增加了条件类型、改进的 key 和交叉类型支持。

为什么使用 TypeScript?

以下是使用 TypeScript 的重要优点/好处

  • JavaScript 中大型复杂项目难以编写和维护。
  • TypeScript 在代码组织方面提供了很大帮助,并且在编译过程中消除了大多数错误。
  • TypeScript 支持 JS 库和 API 文档
  • 它是一种可选类型的脚本语言
  • TypeScript 代码可以转换为纯 JavaScript 代码
  • 更好的代码结构和面向对象编程技术
  • 允许更好的开发时间工具支持
  • 它可以将语言扩展到标准 decorators、async/await 之外

谁使用 TypeScript?

以下是一些最常见的 TypeScript 应用

  • Angular 团队使用 TypeScript。
  • NodeJS 和 NPM 安装
  • TypeScript 安装
  • 将 TypeScript 代码编译为 JavaScript
  • 使用 Nodejs 执行代码
  • 在浏览器中执行 JavaScript
  • 使用 EcmaScript 版本将 TypeScript 代码编译为 JavaScript
  • 您可以使用 NodeJS 轻松地将 TypeScript 代码编译为 JavaScript。
  • 因此,要使用 TypeScript,您首先需要下载和安装 NodeJS。

摘要

  • TypeScript 是 JavaScript 的超集。TypeScript 是一种纯面向对象的编程语言,支持类、接口等。
  • TypeScript 支持所有已发布的 Ecmascript 功能,开发人员可以在编码时使用它们。
  • 变量用于存储值,值可以是字符串、数字、布尔值或表达式。
  • 在 TypeScript 中,变量的类型在开始时就已定义,并且在整个执行过程中,它必须保持相同的类型,任何更改都会在编译到 JavaScript 时导致编译时错误。
  • TypeScript 中的数组是一种数据类型,您可以在其中存储多个值。
  • Class 是从 ES6 开始添加的一项新功能,因此早期在 JavaScript 中,类类型功能是通过带有原型功能的函数来实现代码重用。
  • TypeScript 支持类的方法和属性的 public、private 和 protected 访问修饰符。
  • TypeScript 的核心功能之一是接口。接口是一组规则定义,需要由使用它的实体实现。
  • 函数是一组用于执行任务的指令。
  • TypeScript Enum 是一个对象,其中包含一组相关的已存储值。