• [技术干货] TypeScript接口:定义数据结构的契约-转载
     引言 在软件开发过程中,数据结构是不可避免的。不同的数据结构用于描述不同的实体和关系。定义数据结构有时需要更为精确和严格的方式,以避免在多人合作或迭代过程中出现误解和错误。在这种情况下, TypeScript 接口就成为了一种强有力的工具,可以定义数据结构的契约,从而确保数据在应用程序中的正确性和可维护性。  但是,仅仅使用基本类型、数组和对象等数据类型并不足以满足复杂应用程序中的数据结构需求。这时, TypeScript 接口就可以派上用场了。  什么是接口 在 TypeScript 中,接口是指一组方法和属性的声明,用于定义一个对象的形状。它只定义了对象所应该有的成员,而不关心对象的具体实现。接口可以被类、函数、对象等各种类型实现,从而使得这些实现具有相同的形状和属性。 使用接口可以方便地定义类型,从而避免了在代码中使用硬编码来定义对象的类型。它可以让代码更加清晰、可读、可维护,同时也可以提高代码的复用性和可扩展性。 接口的定义 接口的定义使用 interface 关键字,语法如下: interface InterfaceName {     property1: type1;     property2: type2;     method1(param1: type1, param2: type2): returnType;     method2(param1: type1): void; } 其中,InterfaceName 指定了接口的名称,property1、property2 是接口的属性,method1、method2 是接口的方法。属性和方法都有自己的名称和类型声明。 下面是一个简单的接口定义例子: interface Person {     name: string;     age: number;     sayHi(): void; } 这个接口定义了一个 Person 类型,它有两个属性和一个方法。 name 和 age 属性分别是字符串和数字类型, sayHi 方法没有参数,返回值为空。 接口的实现 在 TypeScript 中,接口可以被任何类型实现,包括类、函数、对象等。当一个类型实现了某个接口时,它必须满足该接口的所有定义,包括属性和方法的类型和名称。 下面是一个类实现接口的例子: interface Person {     name: string;     age: number;     sayHi(): void; }  class Student implements Person {     name: string;     age: number;     constructor(name: string, age: number) {         this.name = name;         this.age = age;     }     sayHi(): void {         console.log(`Hi, my name is ${this.name}, I'm ${this.age} years old.`);     } }  const student = new Student("Alice", 18); student.sayHi(); 在这个例子中,我们定义了一个 Person 接口,并让Student类实现了该接口。在Student类中,我们定义了 name 和 age 属性,并实现了 sayHi 方法。由于 Student 类实现了 Person 接口,因此它必须满足接口的所有定义。在实例化这个类时,可以看到输出了正确的信息。 TypeScript接口的继承 TypeScript 接口也可以 继承其他接口 ,从而可以更好地描述数据结构的关系。以下是一个继承接口的例子: interface Cancer {     name: string;     symptom: string; }  interface LungCancer extends Cancer {     smoking: boolean; } 上面的代码定义了两个接口,“ Cancer ”和“ LungCancer ”。显然,“ LungCancer ”继承了“ Cancer ”的属性,并增加了一个“ smoking ”属性。这种方式可以方便地描述数据结构的层次关系。 接口的可选属性和只读属性 可选属性 有时候我们定义的数据结构并不一定需要所有的属性,在这种情况下,我们可以使用可选属性。可选属性在属性名后面加上一个 ? 标记,表示该属性是可选的。例如: interface Person {     name: string;     age?: number;     sayHi(): void; }  const person1: Person = {     name: "Bob",     sayHi() {         console.log(`Hi, my name is ${this.name}.`);     }, };  const person2: Person = {     name: "Alice",     age: 18,     sayHi() {         console.log(`Hi, my name is ${this.name}, I'm ${this.age} years old.`);     }, }; 在这个例子中, Person 接口的 age 属性是可选的,因此我们可以在实现该接口的对象中省略 age 属性。在上面的 person1 对象中,我们只实现了 name 和 sayHi 属性,而没有实现 age 属性。在 person2 对象中,我们实现了所有的属性和方法。 只读属性 另外,有些时候我们希望定义一些只读的属性,这些属性只能在声明时被赋值,之后就不能被修改了。在 TypeScript 中,我们可以使用 readonly 关键字来定义只读属性。例如: interface Person {     readonly name: string;     age?: number;     sayHi(): void; }  const person: Person = {     name: "Alice",     age: 18,     sayHi() {         console.log(`Hi, my name is ${this.name}, I'm ${this.age} years old.`);     }, };  在这个例子中,我们定义了一个 Person 接口,并将 name 属性定义为只读属性。在实现该接口的对象中,我们无法修改 name 属性的值,因此在赋值时会出现编译错误。 TypeScript接口的函数类型 在 TypeScript 中,接口不仅可以描述对象,还可以描述函数类型。以下是一个函数类型的例子: interface SearchFunc {     (source: string, subString: string): boolean; }  let mySearch: SearchFunc; mySearch = function(source: string, subString: string): boolean {     let result = source.search(subString);     return result > -1; } 上面的代码定义了一个函数类型的接口“ SearchFunc ”,它描述了一个具有两个参数和一个布尔类型返回值的函数。在实例化这个函数类型的时候,“ mySearch ”变量被赋值为符合这个函数类型的函数。 TypeScript接口的类类型 在 TypeScript 中,接口还可以描述类的属性和方法。以下是一个例子: interface ClockInterface {     currentTime: Date;     setTime(d: Date): void; }  class Clock implements ClockInterface {     currentTime: Date = new Date();     setTime(d: Date) {         this.currentTime = d;     }     constructor(h: number, m: number) {     } } 上面的代码定义了一个接口“ ClockInterface ”,它描述了一个具有“ currentTime ”和“ setTime ”方法的类。然后,我们定义了一个“ Clock ”类,并实现了这个接口。当我们实例化这个类的时候,它必须符合接口的描述,即含有“ currentTime ”属性和“ setTime ”方法。 总结 在 TypeScript 中,接口是定义数据结构的契约,用于确保代码的健壮性和可维护性。它可以被任何类型实现,包括类、函数、对象等。接口可以定义属性、方法、可选属性、只读属性等,从而使代码更加清晰、可读、可维护。接口的使用可以提高代码的复用性和可扩展性,是 TypeScript 中一个非常重要的概念。 ———————————————— 版权声明:本文为CSDN博主「与墨学长」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/McapricornZ/article/details/131340880 
  • [其他问题] typescript中定义枚举变量,赋值报错是怎么回事?
    下面的给nodeInfo.nodeType中的枚举变量赋值怎么会报错?定义:interface IPlayer {playerName:String; playerColor:Color;}export const enum enumNodeType {Troop, City}interface nodeInfo {playerInfo:IPlayer; nodeType:enumNodeType}在函数中使用:let nodeInfo:nodeInfo;nodeInfo.nodeType = enumNodeType.City  // 这里报错,是怎么回事?同一个文件中
  • [技术干货] TypeScript 这十年-转载
    【CSDN 编者按】很多时候,仅从名称上来看,不少人对 TypeScript 与 JavaScript 傻傻分不清楚,或许只知道 TypeScript 作为 JavaScript 的后来者,想要将其取而代之,却时至今日未能如愿。殊不知,TypeScript 诞生落地发展到当下,已有十年的时间。虽然未能达到 JavaScript 流行的高度,但也弥补了其不少不足之处。近日,微软 TypeScript 高级项目经理 Daniel Rosenwasser 在官网发文分享了 TypeScript 从早期到时间考验再到今天的整个演进历程,也带来了不一样的思考。原文地址:https://devblogs.microsoft.com/typescript/ten-years-of-typescript/编译 | 苏宓 出品 | CSDN(ID:CSDNnews)以下为译文:今天是 TypeScript 的生日!但是这个生日很特别——10 年前的今天,2012 年 10 月 1 日,TypeScript 首次公开亮相。早期的情况当 TypeScript 首次亮相时,有很多人持怀疑态度,这也是可以理解的。对于一些 JavaScript 用户来说,一个试图将静态类型引入 JavaScript 的团队可能听起来像是一个邪恶的组织,甚至可视为一个阴谋或笑话。但是这些功能是有价值的,对吗?类型检查,在你保存文件之前捕捉 Bug,并获得丰富的编辑器功能,如代码完成、导航和重构?我们知道公司内外部的团队在处理复杂的 JavaScript 代码库时遇到了巨大的挑战,而且我们知道 JavaScript 将被广泛使用。因此,谁不希望有强大的工具来帮助编写它呢?对于团队来说,TypeScript 初心未变,一如最初在发布 TypeScript 时所述的那样,“在大型应用开发中使用 JavaScript 开发!"。幸运的是,这个愿景使得很多的开发者产生了共鸣。在早期,我们建立了一个小而勤奋、热情的社区,当我们还在迭代、学习和构建一个甚至还没有达到 1.0 的东西时,很多人就愿意参与进来,进行实验和体验。我们看到了令人兴奋的新努力,如 DefinitelyTyped 项目,新的社区成员在 StackOverflow 和我们的问题跟踪器上提供帮助,创作者为该语言编写书籍和教程,以及押注 TypeScript 的新库。这些有耐心、努力工作、精力充沛的开发者为 TypeScript 社区的发展奠定了基础。不过,大多数 JavaScript 开发人员对 TypeScript 仍持怀疑态度。那么,这个团队要如何说服 JavaScript 开发者相信静态类型在动态类型语言中的价值?"类型与无类型"一直是一个有争议的话题,这在编程界至少可以追溯到半个世纪以前。但是,我们真的想通过类型的力量来创造令人惊奇的 JavaScript 工具。这能做到吗?经得起时间的考验事实是,这需要一种与我们习惯的完全不同的开发方法,其次是需要大家坚持不懈、拓展性和同理心。TypeScript 必须是免费和开源的,并以真正开放的方式进行。它还必须与现有的 JavaScript 无缝互通,与 JavaScript 共同发展,并且感觉像 JavaScript。TypeScript 从未打算建立一种单独的、独特的、规定性的语言。相反,TypeScript 必须是描述性——围绕 JavaScript 生态系统中一些模式进行类型系统的创新。这让我们能够满足人们的需求,而且这种理念与项目的设计目标非常吻合。实际上,TypeScript 的设计目标保持得如此之好,令人惊讶。例如,一些设计目标:"不会对发出的程序施加任何运行时开销。""与当前和未来的 ECMAScript 提案保持一致。""保留所有 JavaScript 代码的运行时行为。""避免增加表达式级别的语法。""使用一致的、完全可擦除的、结构化的类型系统。"所有真正指向 TypeScript 只是简单地成为 JavaScript 的类型检查器,只添加类型检查所需的语法。因此,我们主要关注类型系统,而避免增加新的运行时语法和行为。这在 10 年后的应用中,体现地可能更明显,但编程语言经常试图根据他们的可运行代码的样子来区分自己。此外,很多类型化语言根据类型来指导他们的运行时行为。但是,这些方法在试图建立在 JavaScript 的基础上,并与之整合时,就没有意义了。没有类型的 JavaScript 在粘贴到 TypeScript 文件中时,必须有相同的工作方式,而且将 TypeScript 转换为 JavaScript 需要像剥离类型一样容易。我们在早期采取了一些错误的措施才意识到这一点,但这是一个学习的机会,并且微软团队在 10 年的大部分时间里都避免了运行时语法。如今,当 TypeScript 缺少一个有用的运行时特性时,我们不会只在 TypeScript 中添加它。我们在 TC39(JavaScript 标准机构)内开始实践,指导或倡导新的功能,以便所有的 JavaScript 开发人员能够从中受益。另一个成功的原则是,TypeScript 并没有试图成为工具箱中的每一个工具。我们的一个非目标是不 "提供一个端到端的构建管道。相反,使系统具有可扩展性,以便外部工具可以使用编译器进行更复杂的构建工作流程"。有很多时候,TypeScript 被要求成为一个 linter、一个 bundler、一个优化器/minifier、一个构建协调器、再一个 bundler 等等。这些界限并不会每次被明确,尤其是当 TypeScript 作为一个类型检查器、编译器和语言服务已经做了很多。在 JavaScript 生态系统中,很多人参与到应用程序开发的最佳实践争斗中,由此 TypeScript 也不断地保持了灵活性,这一点非常重要。考虑到过去几年中,所有不同的捆绑器、不同的运行时、不同的构建协调器和不同的锁定器,TypeScript 与其中的每一个都很好地整合了,并没有试图取代其中的任何一个,这一点也至关重要。我们很荣幸能与这个领域的工具作者合作,因为我们都在努力使 TypeScript 和 JavaScript 更容易使用。回到今天今天,TypeScript 是一种蓬勃发展的语言,全世界有数百万的开发人员在使用。在 StackOverflow 的年度调查、GitHub 的 Octoverse 报告和 Redmonk的语言排名等调查和语言排名中,TypeScript 一直处于开发者最常用和最喜爱的语言中的 Top 10。当然,背景很重要——TypeScript 的使用从根本上与 JavaScript 的使用交织在一起,每个 TypeScript 开发者也是 JavaScript 开发者。值得庆幸的是,即使在询问 JavaScript 开发人员是否使用 TypeScript 并喜欢它时,比如在 JS 的状态调查中,答案也都会是 "是"!TypeScript 的成功是一个很好的例子。今天的成功远远超过了核心团队几年前对 TypeScript 的想象,更不用说十年前了。核心团队在 TypeScript 上努力工作,但我们知道,实现这一成功的根本原因是社区。这包括 TypeScript 的外部贡献者、在 TypeScript 上下注并证明该语言的库创建者和日常开发者、DefinitelyTyped 的贡献者、社区组织者、花时间回答问题和教导他人并为新人开辟道路的专家。也希望 TypeScript 的下一个 10 年能给你带来好的待遇!原文链接:https://blog.csdn.net/csdnnews/article/details/127236749?spm=1000.2115.3001.5927
  • [热门活动] C#、TypeScript 之父 Anders Hejlsberg:“会用 Excel 的,都是程序员 ”[转载]
    原文链接:https://thenewstack.io/microsofts-programming-language-czar-anders-hejlsberg-the-interview/                 https://blog.csdn.net/m0_66023967/article/details/123068356?spm=1000.2115.3001.5927Anders Hejlsberg是世界上最重要的计算机程序员之一。作为Turbo Pascal、Delphi、C#和TypeScript等编程语言的创造者,在构建微软.NET等开发环境方面极具影响力,Hejlsberg影响了数以百万计的软件开发人员。近日,Hejlsberg与TNS新闻编辑Darryl K.Taft进行了一场线上对话,围绕微软低代码/无代码、Web3等话题,分享了他对许多与软件开发相关的事情的看法。Excel是一种低代码/无代码工具问:您对于低代码,无代码有什么看法?Anders Hejlsberg:我认为这个领域的潜力巨大。我们常会忽略,其实我们已经拥有了世界上最好的编程语言之一,或许这取决于你如何定义Excel中编程语言。可以说Excel是一种低代码/无代码的程序编写方式,人们运行程序,而他们使用的电子表格就是程序。你可以做一些事情,输入一些东西,然后运行程序,程序会在电子表格的底层运行,并且给出结果。所以我认为挑战其实一直在于这些工具。当达到低代码环境的极限时,你需要找到设置合适的逃生舱口的方法,才不会陷入困境。而且这个逃生舱口,可以转移到一个更完整或完整的编程环境,这意味着有意义的可扩展性模型是必须的。因此,我们需要思考的事情还有很多,但这些事情往往不是最重要的,因为人们往往会转而关注绘制方框和线条,以及这些示例的演示效果。但我常常很好奇,这些工具是否能适应现实世界?很多都不能,但有些可以。这是有趣的地方。问:我的意思是,整体的主旨是努力让更多人进入开发的世界。其中一部分人想要走的更远,成为专业人士,或者至少更加熟练。Anders Hejlsberg:是的。如果你去问所有的Excel用户,他们都不会自称程序员。但是,从某种意义上来说,他们是。问:没错,我比较喜欢把这比作“Blue Apron”和“HelloFresh”这样的套餐服务——它们会让你开始学习烹饪,并且自己动手,做得更好。你认为在软件开发中下一个要克服的挑战是什么?Anders Hejlsberg:在我们写代码的方式和机器学习的可能够帮助我们的方式之间,仍然有非常大的差距。因为我们的大脑以及神经网络的工作方式,从来没有真正关于0和1以及绝对正确的答案,而都是统计和模糊逻辑。然而,所有的编程语言都牢固地扎根于逻辑和可证明性等等。这两种世界观之间存在着巨大的差距。看看我们最终如何弥合这一差距的(如果说我们最终做到了的话)。软件开发中的安全性问:下面我们来谈谈安全问题。在软件开发中,安全性和整个shift left的作用有多重要?Anders Hejlsberg:这取决于你在堆栈中的位置。对于编程语言来说,安全性非常重要,起码这对我的工作影响很大。甚至可以说类型检查器是一种安全形式。这是软件中可利用的漏洞。所以从这个意义上来说,编程语言间接地考虑了安全性。创造可以分析代码,并且指出可能存在的安全漏洞的工具,是我们看待安全性的其他方式。但很显然,这是个现实问题。我是说,世界各地也有人每天上班,他们的工作就是黑入西方国家的公司,从而获得薪水。这细思极恐。有很多人靠滥用科技谋生。虽然这一点令人难过,但这就是现实。Web3的开发问:您对Web3有什么看法?您认为是否需要新的工具进行Web3的开发呢?Anders Hejlsberg:首先,我们要对Web3的概念达成共识,因为人们对此总是各持己见。我喜欢奖励创造者概念,以及创造数字资产并获得奖励的能力。但是,在这个领域也有很多骗子、挂羊头卖狗肉的人和急功近利的人。而且还会造成大量的环境污染,虽然可以将其归因于一些正在进行的采矿活动和能源的使用,所以这是一个多样的世界。我们将看到这一切的结果。因此,我喜欢它的某些部分,也反对它的某些部分。潜力巨大的项目:GitHub构建的Copilot问:我知道您在微软需要做的事情很多,但在微软以外,有没有什么很棒的项目或者工作吸引您的关注?Anders Hejlsberg:我认为微软肯定有一些非常有趣的项目。比如开发者工具、人工智能、机器学习,还有很多其他有意思的事。不知道你是否了解GitHub正在构建的Copilot的项目,能够在世界上所有的开源代码上训练一个机器学习网络,然后让它给出答案,是不是很棒?当然,这仍然有点像西大荒,因为有各种机遇和不可掌控的发展,以及知识产权的未解决的问题,但它展现出巨大的潜力。所以我认为这很吸引人,我正在密切关注这个问题。问:我认为这是2021年的最好的编程项目,涉及到相当大的领域。Anders Hejlsberg:是的,这个项目确实很吸引人。尤其是作为一名程序员,它在很大程度上让人洞察到我们谈论的是什么样的智能。从某种意义上说,用智能这个词有点不恰当,因为如果有人以前写过这段代码,这种机器学习模型的聚合内存可能是正确的,这值得我们注意。它可以在其内存中找到那段代码。但是,如果以前没有人写过,它必须要思考解决方案,结果可能出人意料,所以在这方面还有很多需要思考的地方。但这是一个了不起的工具,因为它把再利用的概念提升到了一个新的水平,让我们不用重复做别人已经做过的事。
  • [技术干货] TypeScript 声明文件
    TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。假如我们想使用第三方库,比如 jQuery,我们通常这样获取一个 id 是 foo 的元素:$('#foo');// 或jQuery('#foo');但是在 TypeScript 中,我们并不知道 $ 或 jQuery 是什么东西:jQuery('#foo');// index.ts(1,1): error TS2304: Cannot find name 'jQuery'.这时,我们需要使用 declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对:declare var jQuery: (selector: string) => any;jQuery('#foo');declare 定义的类型只会用于编译时的检查,编译结果中会被删除。上例的编译结果是:jQuery('#foo');声明文件声明文件以 .d.ts 为后缀,例如:runoob.d.ts声明文件或模块的语法格式如下:declare module Module_Name {}TypeScript 引入声明文件语法格式:/// <reference path = " runoob.d.ts" />当然,很多流行的第三方库的声明文件不需要我们定义了,比如 jQuery 已经有人帮我们定义好了:jQuery in DefinitelyTyped。实例以下定义一个第三方库来演示:CalcThirdPartyJsLib.js 文件代码:var Runoob;  (function(Runoob) {    var Calc = (function () {         function Calc() {         }     })    Calc.prototype.doSum = function (limit) {        var sum = 0;          for (var i = 0; i <= limit; i++) {             sum = sum + i;         }        return sum;     }    Runoob.Calc = Calc;     return Calc; })(Runoob || (Runoob = {})); var test = new Runoob.Calc();如果我们想在 TypeScript 中引用上面的代码,则需要设置声明文件 Calc.d.ts,代码如下:Calc.d.ts 文件代码:declare module Runoob {    export class Calc {       doSum(limit:number) : number;    }}声明文件不包含实现,它只是类型声明,把声明文件加入到 TypeScript 中:CalcTest.ts 文件代码:/// <reference path = "Calc.d.ts" /> var obj = new Runoob.Calc(); // obj.doSum("Hello"); // 编译错误console.log(obj.doSum(10));下面这行导致编译错误,因为我们需要传入数字参数:obj.doSum("Hello");使用 tsc 命令来编译以上代码文件:tsc CalcTest.ts生成的 JavaScript 代码如下:CalcTest.js 文件代码:/// <reference path = "Calc.d.ts" /> var obj = new Runoob.Calc();//obj.doSum("Hello"); // 编译错误console.log(obj.doSum(10));
  • [技术干货] typescript 模块
    TypeScript 模块的设计理念是可以更换的组织代码。模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类似地,我们必须通过 import 导入其他模块导出的变量、函数、类等。两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于 Node.js 的 CommonJS 和服务于 Web 应用的 Require.js。此外还有有 SystemJs 和 Webpack。模块导出使用关键字 export 关键字,语法格式如下:// 文件名 : SomeInterface.ts export interface SomeInterface {    // 代码部分}要在另外一个文件使用该模块就需要使用 import 关键字来导入:import someInterfaceRef = require("./SomeInterface");实例IShape.ts 文件代码:/// <reference path = "IShape.ts" /> export interface IShape {    draw(); }Circle.ts 文件代码:import shape = require("./IShape"); export class Circle implements shape.IShape {    public draw() {       console.log("Cirlce is drawn (external module)");    } }Triangle.ts 文件代码:import shape = require("./IShape"); export class Triangle implements shape.IShape {    public draw() {       console.log("Triangle is drawn (external module)");    } }TestShape.ts 文件代码:import shape = require("./IShape"); import circle = require("./Circle"); import triangle = require("./Triangle");   function drawAllShapes(shapeToDraw: shape.IShape) {   shapeToDraw.draw(); }  drawAllShapes(new circle.Circle()); drawAllShapes(new triangle.Triangle());使用 tsc 命令编译以上代码(AMD):tsc --module amd TestShape.ts 得到以下 JavaScript 代码:IShape.js 文件代码:define(["require", "exports"], function (require, exports) {});Circle.js 文件代码:define(["require", "exports"], function (require, exports) {   var Circle = (function () {      function Circle() {      }      Circle.prototype.draw = function () {         console.log("Cirlce is drawn (external module)");      };      return Circle;   })();   exports.Circle = Circle;});Triangle.js 文件代码:define(["require", "exports"], function (require, exports) {   var Triangle = (function () {      function Triangle() {      }      Triangle.prototype.draw = function () {         console.log("Triangle is drawn (external module)");      };      return Triangle;   })();   exports.Triangle = Triangle;});TestShape.js 文件代码:define(["require", "exports", "./Circle", "./Triangle"],    function (require, exports, circle, triangle) {      function drawAllShapes(shapeToDraw) {      shapeToDraw.draw();   }   drawAllShapes(new circle.Circle());   drawAllShapes(new triangle.Triangle());});使用 tsc 命令编译以上代码(Commonjs):tsc --module commonjs TestShape.ts得到以下 JavaScript 代码:Circle.js 文件代码:var Circle = (function () {   function Circle() {   }   Circle.prototype.draw = function () {      console.log("Cirlce is drawn");   };   return Circle;})(); exports.Circle = Circle;Triangle.js 文件代码:var Triangle = (function () {   function Triangle() {   }   Triangle.prototype.draw = function () {      console.log("Triangle is drawn (external module)");   };   return Triangle;})();exports.Triangle = Triangle;TestShape.js 文件代码:var circle = require("./Circle");var triangle = require("./Triangle"); function drawAllShapes(shapeToDraw) {   shapeToDraw.draw();}drawAllShapes(new circle.Circle());drawAllShapes(new triangle.Triangle());输出结果为:Cirlce is drawn (external module)Triangle is drawn (external module)
  • [技术干货] typescript命名空间
    命名空间一个最明确的目的就是解决重名问题。假设这样一种情况,当一个班上有两个名叫小明的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的姓(王小明,李小明),或者他们父母的名字等等。命名空间定义了标识符的可见范围,一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的。这样,在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中。TypeScript 中命名空间使用 namespace 来定义,语法格式如下:namespace SomeNameSpaceName {    export interface ISomeInterfaceName {      }     export class SomeClassName {      }  }以上定义了一个命名空间 SomeNameSpaceName,如果我们需要在外部可以调用 SomeNameSpaceName 中的类和接口,则需要在类和接口添加 export 关键字。要在另外一个命名空间调用语法格式为:SomeNameSpaceName.SomeClassName;如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:/// <reference path = "SomeFileName.ts" />以下实例演示了命名空间的使用,定义在不同文件中:IShape.ts 文件代码:namespace Drawing {     export interface IShape {         draw();     }}Circle.ts 文件代码:/// <reference path = "IShape.ts" /> namespace Drawing {     export class Circle implements IShape {         public draw() {             console.log("Circle is drawn");         }      }}Triangle.ts 文件代码:/// <reference path = "IShape.ts" /> namespace Drawing {     export class Triangle implements IShape {         public draw() {             console.log("Triangle is drawn");         }     } }TestShape.ts 文件代码:/// <reference path = "IShape.ts" />   /// <reference path = "Circle.ts" /> /// <reference path = "Triangle.ts" />  function drawAllShapes(shape:Drawing.IShape) {     shape.draw(); } drawAllShapes(new Drawing.Circle());drawAllShapes(new Drawing.Triangle());使用 tsc 命令编译以上代码:tsc --out app.js TestShape.ts  得到以下 JavaScript 代码:JavaScript/// <reference path = "IShape.ts" /> var Drawing;(function (Drawing) {    var Circle = /** @class */ (function () {        function Circle() {        }        Circle.prototype.draw = function () {            console.log("Circle is drawn");        };        return Circle;    }());    Drawing.Circle = Circle;})(Drawing || (Drawing = {}));/// <reference path = "IShape.ts" /> var Drawing;(function (Drawing) {    var Triangle = /** @class */ (function () {        function Triangle() {        }        Triangle.prototype.draw = function () {            console.log("Triangle is drawn");        };        return Triangle;    }());    Drawing.Triangle = Triangle;})(Drawing || (Drawing = {}));/// <reference path = "IShape.ts" />   /// <reference path = "Circle.ts" /> /// <reference path = "Triangle.ts" />  function drawAllShapes(shape) {    shape.draw();}drawAllShapes(new Drawing.Circle());drawAllShapes(new Drawing.Triangle());使用 node 命令查看输出结果为:$ node app.jsCircle is drawnTriangle is drawn嵌套命名空间命名空间支持嵌套,即你可以将命名空间定义在另外一个命名空间里头。namespace namespace_name1 {     export namespace namespace_name2 {        export class class_name {    }     } }成员的访问使用点号 . 来实现,如下实例:Invoice.ts 文件代码:namespace Runoob {    export namespace invoiceApp {       export class Invoice {          public calculateDiscount(price: number) {             return price * .40;          }       }    } }InvoiceTest.ts 文件代码:/// <reference path = "Invoice.ts" />var invoice = new Runoob.invoiceApp.Invoice(); console.log(invoice.calculateDiscount(500));使用 tsc 命令编译以上代码:tsc --out app.js InvoiceTest.ts得到以下 JavaScript 代码:JavaScriptvar Runoob;(function (Runoob) {    var invoiceApp;    (function (invoiceApp) {        var Invoice = /** @class */ (function () {            function Invoice() {            }            Invoice.prototype.calculateDiscount = function (price) {                return price * .40;            };            return Invoice;        }());        invoiceApp.Invoice = Invoice;    })(invoiceApp = Runoob.invoiceApp || (Runoob.invoiceApp = {}));})(Runoob || (Runoob = {}));/// <reference path = "Invoice.ts" />var invoice = new Runoob.invoiceApp.Invoice();console.log(invoice.calculateDiscount(500));使用 node 命令查看输出结果为:$ node app.js200
  • [技术干货] TypeScript 类(下)
    继承类的方法重写类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。其中 super 关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。TypeScriptclass PrinterClass {    doPrint():void {      console.log("父类的 doPrint() 方法。")    } }  class StringPrinter extends PrinterClass {    doPrint():void {       super.doPrint() // 调用父类的函数      console.log("子类的 doPrint()方法。")   } }编译以上代码,得到以下 JavaScript 代码:JavaScriptvar obj = new StringPrinter() obj.doPrint() var __extends = (this && this.__extends) || (function () {    var extendStatics = function (d, b) {        extendStatics = Object.setPrototypeOf ||            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };        return extendStatics(d, b);    };    return function (d, b) {        extendStatics(d, b);        function __() { this.constructor = d; }        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());    };})();var PrinterClass = /** @class */ (function () {    function PrinterClass() {    }    PrinterClass.prototype.doPrint = function () {        console.log("父类的 doPrint() 方法。");    };    return PrinterClass;}());var StringPrinter = /** @class */ (function (_super) {    __extends(StringPrinter, _super);    function StringPrinter() {        return _super !== null && _super.apply(this, arguments) || this;    }    StringPrinter.prototype.doPrint = function () {        _super.prototype.doPrint.call(this); // 调用父类的函数        console.log("子类的 doPrint()方法。");    };    return StringPrinter;}(PrinterClass));var obj = new StringPrinter();obj.doPrint();输出结果为:父类的 doPrint() 方法。子类的 doPrint()方法。static 关键字static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。TypeScriptclass StaticMem {     static num:number;       static disp():void {       console.log("num 值为 "+ StaticMem.num)    } }  StaticMem.num = 12     // 初始化静态变量StaticMem.disp()       // 调用静态方法编译以上代码,得到以下 JavaScript 代码:JavaScriptvar StaticMem = /** @class */ (function () {    function StaticMem() {    }    StaticMem.disp = function () {        console.log("num 值为 " + StaticMem.num);    };    return StaticMem;}());StaticMem.num = 12; // 初始化静态变量StaticMem.disp(); // 调用静态方法输出结果为:num 值为 12instanceof 运算符instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。TypeScriptclass Person{ } var obj = new Person() var isPerson = obj instanceof Person; console.log("obj 对象是 Person 类实例化来的吗? " + isPerson);编译以上代码,得到以下 JavaScript 代码:JavaScriptvar Person = /** @class */ (function () {    function Person() {    }    return Person;}());var obj = new Person();var isPerson = obj instanceof Person;console.log(" obj 对象是 Person 类实例化来的吗? " + isPerson);输出结果为:obj 对象是 Person 类实例化来的吗? true访问控制修饰符TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。public(默认) : 公有,可以在任何地方被访问。protected : 受保护,可以被其自身以及其子类和父类访问。private : 私有,只能被其定义所在的类访问。以下实例定义了两个变量 str1 和 str2,str1 为 public,str2 为 private,实例化后可以访问 str1,如果要访问 str2 则会编译错误。TypeScriptclass Encapsulate {    str1:string = "hello"    private str2:string = "world" } var obj = new Encapsulate() console.log(obj.str1)     // 可访问 console.log(obj.str2)   // 编译错误, str2 是私有的类和接口类可以实现接口,使用关键字 implements,并将 interest 字段作为类的属性使用。以下实例红 AgriLoan 类实现了 ILoan 接口:TypeScriptinterface ILoan {    interest:number }  class AgriLoan implements ILoan {    interest:number    rebate:number       constructor(interest:number,rebate:number) {       this.interest = interest       this.rebate = rebate    } }  var obj = new AgriLoan(10,1) console.log("利润为 : "+obj.interest+",抽成为 : "+obj.rebate )编译以上代码,得到以下 JavaScript 代码:JavaScriptvar AgriLoan = /** @class */ (function () {    function AgriLoan(interest, rebate) {        this.interest = interest;        this.rebate = rebate;    }    return AgriLoan;}());var obj = new AgriLoan(10, 1);console.log("利润为 : " + obj.interest + ",抽成为 : " + obj.rebate);输出结果为:利润为 : 10,抽成为 : 1
  • [技术干货] TypeScript 类
    TypeScript 是面向对象的 JavaScript。类描述了所创建的对象共同的属性和方法。TypeScript 支持面向对象的所有特性,比如 类、接口等。TypeScript 类定义方式如下:class class_name {     // 类作用域}定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):字段 − 字段是类里面声明的变量。字段表示对象的有关数据。构造函数 − 类实例化时调用,可以为类的对象分配内存。方法 − 方法为对象要执行的操作。实例创建一个 Person 类:TypeScriptclass Person {}编译以上代码,得到以下 JavaScript 代码:JavaScriptvar Person = /** @class */ (function () {    function Person() {    }    return Person;}());创建类的数据成员以下实例我们声明了类 Car,包含字段为 engine,构造函数在类实例化后初始化字段 engine。this 关键字表示当前类实例化的对象。注意构造函数的参数名与字段名相同,this.engine 表示类的字段。此外我们也在类中定义了一个方法 disp()。TypeScriptclass Car {     // 字段     engine:string;      // 构造函数     constructor(engine:string) {         this.engine = engine     }       // 方法     disp():void {         console.log("发动机为 :   "+this.engine)     } }编译以上代码,得到以下 JavaScript 代码:JavaScriptvar Car = /** @class */ (function () {    // 构造函数     function Car(engine) {        this.engine = engine;    }    // 方法     Car.prototype.disp = function () {        console.log("发动机为 :   " + this.engine);    };    return Car;}());创建实例化对象我们使用 new 关键字来实例化类的对象,语法格式如下:var object_name = new class_name([ arguments ])类实例化时会调用构造函数,例如:var obj = new Car("Engine 1")类中的字段属性和方法可以使用 . 号来访问:// 访问属性obj.field_name // 访问方法obj.function_name()完整实例以下实例创建来一个 Car 类,然后通过关键字 new 来创建一个对象并访问属性和方法:TypeScriptclass Car {    // 字段   engine:string;       // 构造函数   constructor(engine:string) {       this.engine = engine    }        // 方法   disp():void {       console.log("函数中显示发动机型号  :   "+this.engine)    } }  // 创建一个对象var obj = new Car("XXSY1") // 访问字段console.log("读取发动机型号 :  "+obj.engine)   // 访问方法obj.disp()编译以上代码,得到以下 JavaScript 代码:JavaScriptvar Car = /** @class */ (function () {    // 构造函数    function Car(engine) {        this.engine = engine;    }    // 方法    Car.prototype.disp = function () {        console.log("函数中显示发动机型号  :   " + this.engine);    };    return Car;}());// 创建一个对象var obj = new Car("XXSY1");// 访问字段console.log("读取发动机型号 :  " + obj.engine);// 访问方法obj.disp();输出结果为:读取发动机型号 :  XXSY1函数中显示发动机型号  :   XXSY1类的继承TypeScript 支持继承类,即我们可以在创建类的时候继承一个已存在的类,这个已存在的类称为父类,继承它的类称为子类。类继承使用关键字 extends,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。TypeScript 一次只能继承一个类,不支持继承多个类,但 TypeScript 支持多重继承(A 继承 B,B 继承 C)。语法格式如下:class child_class_name extends parent_class_name实例类的继承:实例中创建了 Shape 类,Circle 类继承了 Shape 类,Circle 类可以直接使用 Area 属性:TypeScriptclass Shape {    Area:number       constructor(a:number) {       this.Area = a    } }  class Circle extends Shape {    disp():void {       console.log("圆的面积:  "+this.Area)    } }  var obj = new Circle(223); obj.disp()编译以上代码,得到以下 JavaScript 代码:JavaScriptvar __extends = (this && this.__extends) || (function () {    var extendStatics = function (d, b) {        extendStatics = Object.setPrototypeOf ||            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };        return extendStatics(d, b);    };    return function (d, b) {        extendStatics(d, b);        function __() { this.constructor = d; }        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());    };})();var Shape = /** @class */ (function () {    function Shape(a) {        this.Area = a;    }    return Shape;}());var Circle = /** @class */ (function (_super) {    __extends(Circle, _super);    function Circle() {        return _super !== null && _super.apply(this, arguments) || this;    }    Circle.prototype.disp = function () {        console.log("圆的面积:  " + this.Area);    };    return Circle;}(Shape));var obj = new Circle(223);obj.disp();输出结果为:圆的面积:  223需要注意的是子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承,如下实例:TypeScriptclass Root {    str:string; }  class Child extends Root {} class Leaf extends Child {} // 多重继承,继承了 Child 和 Root 类 var obj = new Leaf(); obj.str ="hello" console.log(obj.str)编译以上代码,得到以下 JavaScript 代码:JavaScriptvar __extends = (this && this.__extends) || (function () {    var extendStatics = function (d, b) {        extendStatics = Object.setPrototypeOf ||            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };        return extendStatics(d, b);    };    return function (d, b) {        extendStatics(d, b);        function __() { this.constructor = d; }        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());    };})();var Root = /** @class */ (function () {    function Root() {    }    return Root;}());var Child = /** @class */ (function (_super) {    __extends(Child, _super);    function Child() {        return _super !== null && _super.apply(this, arguments) || this;    }    return Child;}(Root));var Leaf = /** @class */ (function (_super) {    __extends(Leaf, _super);    function Leaf() {        return _super !== null && _super.apply(this, arguments) || this;    }    return Leaf;}(Child)); // 多重继承,继承了 Child 和 Root 类var obj = new Leaf();obj.str = "hello";console.log(obj.str);输出结果为:hello
  • [技术干货] TypeScript 接口
    接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。TypeScript 接口定义如下:interface interface_name { }实例以下实例中,我们定义了一个接口 IPerson,接着定义了一个变量 customer,它的类型是 IPerson。customer 实现了接口 IPerson 的属性和方法。TypeScriptinterface IPerson {     firstName:string,     lastName:string,     sayHi: ()=>string }  var customer:IPerson = {     firstName:"Tom",    lastName:"Hanks",     sayHi: ():string =>{return "Hi there"} }  console.log("Customer 对象 ") console.log(customer.firstName) console.log(customer.lastName) console.log(customer.sayHi())   var employee:IPerson = {     firstName:"Jim",    lastName:"Blakes",     sayHi: ():string =>{return "Hello!!!"} }  console.log("Employee  对象 ") console.log(employee.firstName) console.log(employee.lastName)需要注意接口不能转换为 JavaScript。 它只是 TypeScript 的一部分。编译以上代码,得到以下 JavaScript 代码:JavaScriptvar customer = {    firstName: "Tom",    lastName: "Hanks",    sayHi: function () { return "Hi there"; }};console.log("Customer 对象 ");console.log(customer.firstName);console.log(customer.lastName);console.log(customer.sayHi());var employee = {    firstName: "Jim",    lastName: "Blakes",    sayHi: function () { return "Hello!!!"; }};console.log("Employee  对象 ");console.log(employee.firstName);console.log(employee.lastName);输出结果为:Customer 对象TomHanksHi thereEmployee  对象JimBlakes联合类型和接口以下实例演示了如何在接口中使用联合类型:TypeScriptinterface RunOptions {     program:string;     commandline:string[]|string|(()=>string); }  // commandline 是字符串var options:RunOptions = {program:"test1",commandline:"Hello"}; console.log(options.commandline)   // commandline 是字符串数组options = {program:"test1",commandline:["Hello","World"]}; console.log(options.commandline[0]); console.log(options.commandline[1]);   // commandline 是一个函数表达式options = {program:"test1",commandline:()=>{return "**Hello World**";}};  var fn:any = options.commandline; console.log(fn());编译以上代码,得到以下 JavaScript 代码:JavaScript// commandline 是字符串var options = { program: "test1", commandline: "Hello" };console.log(options.commandline);// commandline 是字符串数组options = { program: "test1", commandline: ["Hello", "World"] };console.log(options.commandline[0]);console.log(options.commandline[1]);// commandline 是一个函数表达式options = { program: "test1", commandline: function () { return "**Hello World**"; } };var fn = options.commandline;console.log(fn());输出结果为:HelloHelloWorld**Hello World**接口和数组接口中我们可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串。TypeScriptinterface namelist {    [index:number]:string }  var list2:namelist = ["John",1,"Bran"] // 错误元素 1 不是 string 类型interface ages {    [index:string]:number }  var agelist:ages; agelist["John"] = 15   // 正确 agelist[2] = "nine"   // 错误接口继承接口继承就是说接口可以通过其他接口来扩展自己。Typescript 允许接口继承多个接口。继承使用关键字 extends。单接口继承语法格式:Child_interface_name extends super_interface_name多接口继承语法格式:Child_interface_name extends super_interface1_name, super_interface2_name,…,super_interfaceN_name继承的各个接口使用逗号 , 分隔。单继承实例TypeScriptinterface Person {    age:number }  interface Musician extends Person {    instrument:string }  var drummer = <Musician>{}; drummer.age = 27 drummer.instrument = "Drums" console.log("年龄:  "+drummer.age)console.log("喜欢的乐器:  "+drummer.instrument)编译以上代码,得到以下 JavaScript 代码:JavaScriptvar drummer = {};drummer.age = 27;drummer.instrument = "Drums";console.log("年龄:  " + drummer.age);console.log("喜欢的乐器:  " + drummer.instrument);输出结果为:年龄:  27喜欢的乐器:  Drums多继承实例TypeScriptinterface IParent1 {     v1:number }  interface IParent2 {     v2:number }  interface Child extends IParent1, IParent2 { } var Iobj:Child = { v1:12, v2:23} console.log("value 1: "+Iobj.v1+" value 2: "+Iobj.v2)编译以上代码,得到以下 JavaScript 代码:JavaScriptvar Iobj = { v1: 12, v2: 23 };console.log("value 1: " + Iobj.v1 + " value 2: " + Iobj.v2);输出结果为:value 1: 12 value 2: 23
  • [技术干货] TypeScript 联合类型
    联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。注意:只能赋值指定的类型,如果赋值其它类型就会报错。创建联合类型的语法格式如下:Type1|Type2|Type3 实例声明一个联合类型:TypeScriptvar val:string|number val = 12 console.log("数字为 "+ val) val = "Runoob" console.log("字符串为 " + val)编译以上代码,得到以下 JavaScript 代码:JavaScriptvar val;val = 12;console.log("数字为 " + val);val = "Runoob";console.log("字符串为 " + val);输出结果为:数字为 12字符串为 Runoob如果赋值其它类型就会报错:var val:string|number val = true 也可以将联合类型作为函数参数使用:TypeScriptfunction disp(name:string|string[]) {         if(typeof name == "string") {                 console.log(name)         } else {                 var i;                 for(i = 0;i<name.length;i++) {                 console.log(name[i])                }         } } disp("Runoob") console.log("输出数组....") disp(["Runoob","Google","Taobao","Facebook"])编译以上代码,得到以下 JavaScript 代码:JavaScriptfunction disp(name) {        if (typeof name == "string") {                console.log(name);        }        else {                var i;                for (i = 0; i < name.length; i++) {                console.log(name[i]);                }        }}disp("Runoob");console.log("输出数组....");disp(["Runoob", "Google", "Taobao", "Facebook"]);输出结果为:Runoob输出数组....RunoobGoogleTaobaoFacebook联合类型数组我们也可以将数组声明为联合类型:TypeScriptvar arr:number[]|string[]; var i:number; arr = [1,2,4] console.log("**数字数组**")   for(i = 0;i<arr.length;i++) {    console.log(arr[i]) }   arr = ["Runoob","Google","Taobao"] console.log("**字符串数组**")   for(i = 0;i<arr.length;i++) {    console.log(arr[i]) }编译以上代码,得到以下 JavaScript 代码:JavaScriptvar arr;var i;arr = [1, 2, 4];console.log("**数字数组**");for (i = 0; i < arr.length; i++) {    console.log(arr[i]);}arr = ["Runoob", "Google", "Taobao"];console.log("**字符串数组**");for (i = 0; i < arr.length; i++) {    console.log(arr[i]);}输出结果为:**数字数组**124**字符串数组**RunoobGoogleTaobao
  • [技术干货] TypeScript Array(数组)
    数组对象是使用单独的变量名来存储一系列的值。数组非常常用。假如你有一组数据(例如:网站名字),存在单独变量如下所示:var site1="Google";var site2="Runoob";var site3="Taobao";如果有 10 个、100 个这种方式就变的很不实用,这时我们可以使用数组来解决:var sites:string[]; sites = ["Google","Runoob","Taobao"]这样看起来就简洁多了。TypeScript 声明数组的语法格式如下所示:var array_name[:datatype];        //声明 array_name = [val1,val2,valn..]   //初始化或者直接在声明时初始化:var array_name[:data type] = [val1,val2…valn]如果数组声明时未设置类型,则会被认为是 any 类型,在初始化时根据第一个元素的类型来推断数组的类型。实例创建一个 number 类型的数组:var numlist:number[] = [2,4,6,8]TypeScriptvar sites:string[]; sites = ["Google","Runoob","Taobao"] console.log(sites[0]); console.log(sites[1]);编译以上代码,得到以下 JavaScript 代码:JavaScriptvar sites;sites = ["Google", "Runoob", "Taobao"];console.log(sites[0]);console.log(sites[1]);输出结果为:GoogleRunoob以下实例我们在声明时直接初始化:TypeScriptvar nums:number[] = [1,2,3,4] console.log(nums[0]); console.log(nums[1]); console.log(nums[2]); console.log(nums[3]);编译以上代码,得到以下 JavaScript 代码:JavaScriptvar nums = [1, 2, 3, 4];console.log(nums[0]);console.log(nums[1]);console.log(nums[2]);console.log(nums[3]);输出结果为:1 2 3 4 Array 对象我们也可以使用 Array 对象创建数组。Array 对象的构造函数接受以下两种值:表示数组大小的数值。初始化的数组列表,元素使用逗号分隔值。实例指定数组初始化大小:TypeScriptvar arr_names:number[] = new Array(4)   for(var i = 0; i<arr_names.length; i++) {         arr_names[i] = i * 2         console.log(arr_names[i]) }编译以上代码,得到以下 JavaScript 代码:JavaScriptvar arr_names = new Array(4);for (var i = 0; i < arr_names.length; i++) {        arr_names[i] = i * 2;        console.log(arr_names[i]);}输出结果为:0246以下实例我们直接初始化数组元素:TypeScriptvar sites:string[] = new Array("Google","Runoob","Taobao","Facebook")  for(var i = 0;i<sites.length;i++) {         console.log(sites[i]) }编译以上代码,得到以下 JavaScript 代码:JavaScriptvar sites = new Array("Google", "Runoob", "Taobao", "Facebook");for (var i = 0; i < sites.length; i++) {        console.log(sites[i]);}输出结果为:GoogleRunoobTaobaoFacebook数组解构我们也可以把数组元素赋值给变量,如下所示:TypeScriptvar arr:number[] = [12,13] var[x,y] = arr // 将数组的两个元素赋值给变量 x 和 yconsole.log(x) console.log(y)编译以上代码,得到以下 JavaScript 代码:JavaScriptvar arr = [12, 13];var x = arr[0], y = arr[1]; // 将数组的两个元素赋值给变量 x 和 yconsole.log(x);console.log(y);输出结果为:1213数组迭代我们可以使用 for 语句来循环输出数组的各个元素:TypeScriptvar j:any; var nums:number[] = [1001,1002,1003,1004]  for(j in nums) {     console.log(nums[j]) }编译以上代码,得到以下 JavaScript 代码:JavaScriptvar j;var nums = [1001, 1002, 1003, 1004];for (j in nums) {    console.log(nums[j]);}输出结果为:1001100210031004多维数组一个数组的元素可以是另外一个数组,这样就构成了多维数组(Multi-dimensional Array)。最简单的多维数组是二维数组,定义方式如下:var arr_name:datatype[][]=[ [val1,val2,val3],[v1,v2,v3] ]TypeScriptvar multi:number[][] = [[1,2,3],[23,24,25]]  console.log(multi[0][0]) console.log(multi[0][1]) console.log(multi[0][2]) console.log(multi[1][0]) console.log(multi[1][1]) console.log(multi[1][2])编译以上代码,得到以下 JavaScript 代码:JavaScriptvar multi = [[1, 2, 3], [23, 24, 25]];console.log(multi[0][0]);console.log(multi[0][1]);console.log(multi[0][2]);console.log(multi[1][0]);console.log(multi[1][1]);console.log(multi[1][2]);输出结果为:123232425数组在函数中的使用作为参数传递给函数TypeScriptvar sites:string[] = new Array("Google","Runoob","Taobao","Facebook")  function disp(arr_sites:string[]) {        for(var i = 0;i<arr_sites.length;i++) {                 console.log(arr_sites[i])         }  }  disp(sites);编译以上代码,得到以下 JavaScript 代码:JavaScriptvar sites = new Array("Google", "Runoob", "Taobao", "Facebook");function disp(arr_sites) {        for (var i = 0; i < arr_sites.length; i++) {                console.log(arr_sites[i]);        }}disp(sites);输出结果为:GoogleRunoobTaobaoFacebook作为函数的返回值TypeScriptfunction disp():string[] {         return new Array("Google", "Runoob", "Taobao", "Facebook");}  var sites:string[] = disp() for(var i in sites) {         console.log(sites[i]) }编译以上代码,得到以下 JavaScript 代码:JavaScriptfunction disp() {        return new Array("Google", "Runoob", "Taobao", "Facebook");}var sites = disp();for (var i in sites) {        console.log(sites[i]);}输出结果为:GoogleRunoobTaobaoFacebook
  • [技术干货] TypeScript 元组
    我们知道数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。元组中允许存储不同类型的元素,元组可以作为参数传递给函数。创建元组的语法格式如下:var tuple_name = [value1,value2,value3,…value n]实例声明一个元组并初始化:var mytuple = [10,"Runoob"];或者我们可以先声明一个空元组,然后再初始化:var mytuple = []; mytuple[0] = 120 mytuple[1] = 234访问元组元组中元素使用索引来访问,第一个元素的索引值为 0,第二个为 1,以此类推第 n 个为 n-1,语法格式如下:tuple_name[index]实例以下实例定义了元组,包含了数字和字符串两种类型的元素:TypeScriptvar mytuple = [10,"Runoob"]; // 创建元组console.log(mytuple[0]) console.log(mytuple[1])编译以上代码,得到以下 JavaScript 代码:JavaScriptvar mytuple = [10, "Runoob"]; // 创建元组console.log(mytuple[0]);console.log(mytuple[1]);输出结果为:10Runoob元组运算我们可以使用以下两个函数向元组添加新元素或者删除元素:push() 向元组添加元素,添加在最后面。pop() 从元组中移除元素(最后一个),并返回移除的元素。TypeScriptvar mytuple = [10,"Hello","World","typeScript"]; console.log("添加前元素个数:"+mytuple.length)    // 返回元组的大小 mytuple.push(12)                                    // 添加到元组中console.log("添加后元素个数:"+mytuple.length) console.log("删除前元素个数:"+mytuple.length) console.log(mytuple.pop()+" 元素从元组中删除") // 删除并返回删除的元素        console.log("删除后元素个数:"+mytuple.length)编译以上代码,得到以下 JavaScript 代码:JavaScriptvar mytuple = [10, "Hello", "World", "typeScript"];console.log("添加前元素个数:" + mytuple.length); // 返回元组的大小mytuple.push(12); // 添加到元组中console.log("添加后元素个数:" + mytuple.length);console.log("删除前元素个数:" + mytuple.length);console.log(mytuple.pop() + " 元素从元组中删除"); // 删除并返回删除的元素console.log("删除后元素个数:" + mytuple.length);输出结果为:添加前元素个数:4添加后元素个数:5删除前元素个数:512 元素从元组中删除删除后元素个数:4更新元组元组是可变的,这意味着我们可以对元组进行更新操作:TypeScriptvar mytuple = [10, "Runoob", "Taobao", "Google"]; // 创建一个元组console.log("元组的第一个元素为:" + mytuple[0])  // 更新元组元素mytuple[0] = 121     console.log("元组中的第一个元素更新为:"+ mytuple[0])编译以上代码,得到以下 JavaScript 代码:JavaScriptvar mytuple = [10, "Runoob", "Taobao", "Google"]; // 创建一个元组console.log("元组的第一个元素为:" + mytuple[0]);// 更新元组元素mytuple[0] = 121;console.log("元组中的第一个元素更新为:" + mytuple[0]);输出结果为:元组的第一个元素为:10元组中的第一个元素更新为:121解构元组我们也可以把元组元素赋值给变量,如下所示:TypeScriptvar a =[10,"Runoob"] var [b,c] = a console.log( b )    console.log( c )编译以上代码,得到以下 JavaScript 代码:JavaScriptvar a = [10, "Runoob"];var b = a[0], c = a[1];console.log(b);console.log(c);输出结果为:10Runoob
  • [技术干货] TypeScript 元组
    我们知道数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。元组中允许存储不同类型的元素,元组可以作为参数传递给函数。创建元组的语法格式如下:var tuple_name = [value1,value2,value3,…value n]实例声明一个元组并初始化:var mytuple = [10,"Runoob"];或者我们可以先声明一个空元组,然后再初始化:var mytuple = []; mytuple[0] = 120 mytuple[1] = 234访问元组元组中元素使用索引来访问,第一个元素的索引值为 0,第二个为 1,以此类推第 n 个为 n-1,语法格式如下:tuple_name[index]实例以下实例定义了元组,包含了数字和字符串两种类型的元素:TypeScriptvar mytuple = [10,"Runoob"]; // 创建元组console.log(mytuple[0]) console.log(mytuple[1])编译以上代码,得到以下 JavaScript 代码:JavaScriptvar mytuple = [10, "Runoob"]; // 创建元组console.log(mytuple[0]);console.log(mytuple[1]);输出结果为:10Runoob元组运算我们可以使用以下两个函数向元组添加新元素或者删除元素:push() 向元组添加元素,添加在最后面。pop() 从元组中移除元素(最后一个),并返回移除的元素。TypeScriptvar mytuple = [10,"Hello","World","typeScript"]; console.log("添加前元素个数:"+mytuple.length)    // 返回元组的大小 mytuple.push(12)                                    // 添加到元组中console.log("添加后元素个数:"+mytuple.length) console.log("删除前元素个数:"+mytuple.length) console.log(mytuple.pop()+" 元素从元组中删除") // 删除并返回删除的元素        console.log("删除后元素个数:"+mytuple.length)编译以上代码,得到以下 JavaScript 代码:JavaScriptvar mytuple = [10, "Hello", "World", "typeScript"];console.log("添加前元素个数:" + mytuple.length); // 返回元组的大小mytuple.push(12); // 添加到元组中console.log("添加后元素个数:" + mytuple.length);console.log("删除前元素个数:" + mytuple.length);console.log(mytuple.pop() + " 元素从元组中删除"); // 删除并返回删除的元素console.log("删除后元素个数:" + mytuple.length);输出结果为:添加前元素个数:4添加后元素个数:5删除前元素个数:512 元素从元组中删除删除后元素个数:4更新元组元组是可变的,这意味着我们可以对元组进行更新操作:TypeScriptvar mytuple = [10, "Runoob", "Taobao", "Google"]; // 创建一个元组console.log("元组的第一个元素为:" + mytuple[0])  // 更新元组元素mytuple[0] = 121     console.log("元组中的第一个元素更新为:"+ mytuple[0])编译以上代码,得到以下 JavaScript 代码:JavaScriptvar mytuple = [10, "Runoob", "Taobao", "Google"]; // 创建一个元组console.log("元组的第一个元素为:" + mytuple[0]);// 更新元组元素mytuple[0] = 121;console.log("元组中的第一个元素更新为:" + mytuple[0]);输出结果为:元组的第一个元素为:10元组中的第一个元素更新为:121解构元组我们也可以把元组元素赋值给变量,如下所示:TypeScriptvar a =[10,"Runoob"] var [b,c] = a console.log( b )    console.log( c )编译以上代码,得到以下 JavaScript 代码:JavaScriptvar a = [10, "Runoob"];var b = a[0], c = a[1];console.log(b);console.log(c);输出结果为:10Runoob
  • [技术干货] typescript基础类型
    Any 类型任意值是 TypeScript 针对编程时类型不明确的变量使用的一种数据类型,它常用于以下三种情况。1、变量的值会动态改变时,比如来自用户的输入,任意值类型可以让这些变量跳过编译阶段的类型检查,示例代码如下:let x: any = 1;    // 数字类型x = 'I am who I am';    // 字符串类型x = false;    // 布尔类型改写现有代码时,任意值允许在编译时可选择地包含或移除类型检查,示例代码如下:let x: any = 4;x.ifItExists();    // 正确,ifItExists方法在运行时可能存在,但这里并不会检查x.toFixed();    // 正确定义存储各种类型数据的数组时,示例代码如下:let arrayList: any[] = [1, false, 'fine'];arrayList[1] = 100;Null 和 Undefinednull在 JavaScript 中 null 表示 "什么都没有"。null是一个只有一个值的特殊类型。表示一个空对象引用。用 typeof 检测 null 返回是 object。undefined在 JavaScript 中, undefined 是一个没有设置值的变量。typeof 一个没有值的变量会返回 undefined。Null 和 Undefined 是其他任何类型(包括 void)的子类型,可以赋值给其它类型,如数字类型,此时,赋值后的类型会变成 null 或 undefined。而在TypeScript中启用严格的空校验(--strictNullChecks)特性,就可以使得null 和 undefined 只能被赋值给 void 或本身对应的类型,示例代码如下:// 启用 --strictNullCheckslet x: number;x = 1; // 运行正确x = undefined;    // 运行错误x = null;    // 运行错误上面的例子中变量 x 只能是数字类型。如果一个类型可能出现 null 或 undefined, 可以用 | 来支持多种类型,示例代码如下:// 启用 --strictNullCheckslet x: number | null | undefined;x = 1; // 运行正确x = undefined;    // 运行正确x = null;    // 运行正确更多内容可以查看:JavaScript typeof, null, 和 undefinednever 类型never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环),示例代码如下:let x: never;let y: number;// 运行错误,数字类型不能转为 never 类型x = 123;// 运行正确,never 类型可以赋值给 never类型x = (()=>{ throw new Error('exception')})();// 运行正确,never 类型可以赋值给 数字类型y = (()=>{ throw new Error('exception')})();// 返回值为 never 的函数可以是抛出异常的情况function error(message: string): never {    throw new Error(message);}// 返回值为 never 的函数可以是无法被执行到的终止点的情况function loop(): never {    while (true) {}}