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>
使用 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; }
在上面的函数中,添加了函数名,参数是 a1 和 b1,两者都是 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'.
参数 a1 和 b1 是必需参数,如果未按此方式接收,则会引发错误。此外,参数类型和返回类型非常重要,一旦定义就不能更改。
为函数设置可选参数
在 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>
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 是一个对象,其中包含一组相关的已存储值。