30分钟学会TypeScript

Posted mareden

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了30分钟学会TypeScript相关的知识,希望对你有一定的参考价值。

TypeScript可编译为javascript,专为开发大型和复杂应用程序的开发人员设计。TypeScript从C#和Java这样的语言继承了许多编程概念,为强大灵活、弱类型的JavaScript增加了更多的强类型语言的特性。
 
本文适用于熟悉JavaScript同时想要了解TypeScript的人,将介绍语言基本特性和关键功能,并将提供带注释的代码示例,冀希望有助于了解TypeScript。以下为正文。
 
技术图片

使用TypeScript的好处

JavaScript适用范围很广,了解Javascript的情况下还真的需要学习TypeScript吗?从技术上讲,不需要学习TypeScript就可以成为一名优秀的开发人员,不用学习Typtescript也可以。不过,学习TypeScript带来的好处也很多:
  • 由于是静态类型,用TypeScript编写的代码更容易把控、更易于调试。
  • 借助于模块、名称空间和强大的OOP支持,Typescript让大型、复杂的应用程序组织代码更容易。
  • TypeScript对JavaScript有一个编译步骤,可在此编译过程发现各种错误,运行时前就发现代码错误
  • Angular 2框架是用TypeScript编写的,建议开发人员可考虑在项目中使用该语言
还有一点,这一点对很多人来说很重要,也是大家使用TypeScript的主要原因。Angular 2是目前最热门的框架之一,尽管开发人员可以将其与常规JavaScript一起使用,但大多数教程和示例都是用TS编写的。随着Angular 2社区的发展,会有越来越多的人选择TypeScript。
 
来自Google趋势的数据显示TypeScript的近期流行度
 
技术图片
 
技术图片

安装TypeScript

本教程将需要Node.js和Npm。如果尚未安装,请参见这里
安装TypeScript的最简单方法是通过npm。使用以下命令,可全局安装TypeScript软件包,以便TS编译器可用于所有的项目:
npm install 

接下来可以打开终端并运行tsc -v,查看其是否已正确安装。

tsc -v
Version 1.8.10

 

技术图片

支持TypeScript的文本编辑器

TypeScript是开源项目,由Microsoft开发和维护,最初仅在Microsoft的Visual Studio平台中得到支持。如今,有许多文本编辑器和IDE都支持TypeScript语法、支持Auto compelete、支持错误检查、甚至内置编译器。
 
技术图片

编译为JavaScript

TypeScript代码文件扩展名是.ts(JSX代码是.tsx),不能直接在浏览器中运行,需要先翻译为原始的.js。编译过程可通过多种不同方式完成:
  • 终端中使用前面提到的命令行工具tsc
  • 直接在Visual Studio或其IDE和它文本编辑器中。
  • 使用gulp这样的自动化构建任务工具。
第一种方式最简单、最方便,将在本文中使用。
 
下面这条命令将main.ts转换为JavaScript版本main.js。如main.js已经存在,将被覆盖。
tsc main

也可以列出所有文件,或应用通配符来一次编译多个文件:

# Will result in separate .js files: main.js worker.js.
tsc main.ts worker.ts    

# Compiles all .ts files in the current folder. Does NOT work recursively.
tsc *.ts

 

加入--watch选项后,可以自动编译TypeScript文件:
# Initializes a watcher process that will keep main.js up to date.
tsc main.ts --watch

 

有经验的TypeScript用户可创建tsconfig.json文件,包含各种构建设置。处理大量.ts文件的大型项目时,配置文件非常方便,可以自动完成构建过程。可在此处的TypeScript文档中了解到有关tsconfig.json的更多信息
 
技术图片

静态类型

TypeScript的一大特点是对静态类型的支持,开发人员可以声明变量的类型,编译器在运行时保证为变量分配正确的值类型。代码里如声明时类型省略,将从代码自动推断类型。
 
下面的代码样例能看到,变量、函数参数、返回值均可在初始化时定义其类型:
var burger: string = hamburger,     // String 
    calories: number = 300,           // Numeric
    tasty: boolean = true;            // Boolean

// Alternatively, you can omit the type declaration:
// var burger = ‘hamburger‘;

// The function expects a string and an integer.
// It doesn‘t return anything so the type of the function itself is void.

function speak(food: string, energy: number): void {
  console.log("Our " + food + " has " + energy + " calories.");
}

speak(burger, calories);

 

TypeScript会编译为JavaScript,而Javascript不需要知道类型信息,所以在编译生成的Javascript代码里类型信息会删除:
// JavaScript code from the above TS example.

var burger = hamburger,
    calories = 300, 
    tasty = true; 

function speak(food, energy) {
    console.log("Our " + food + " has " + energy + " calories.");
}

speak(burger, calories);
但是,如果在写TypeScript代码时试着写一些有语法错误的代码,编译时tsc会警告我们代码中存在错误。例如:
// The given type is boolean, the provided value is a string.
var tasty: boolean = "I haven‘t tried it yet";
main.ts(1,5): error TS2322: Type string is not assignable to type boolean.
如将错误的参数传递给函数,也会收到错误提示:
function speak(food: string, energy: number): void{
  console.log("Our " + food + " has " + energy + " calories.");
}

// Arguments don‘t match the function parameters.
speak("tripple cheesburger", "a ton of");
main.ts(5,30): error TS2345: Argument of type ‘string‘ is not assignable to parameter of type ‘number‘.
下面是最常用的几种数据类型:
  • Number-所有数值均由数字类型表示,没有整数,浮点数或其他定义。
  • String-文本类型,就像在普通JS字符串中一样,可以用“单引号”或“双引号”括起来。
  • Boolean- truefalse,使用0和1将导致编译错误。
  • Any-这种类型的变量可以将其值设置为字符串,数字或其它任何东西。
  • Arrays-具有两种可能的语法:my_arr: number[];my_arr: Array<number>
  • Void-用于不返回任何内容的函数。
要查看所有可用类型的列表,请访问官方TypeScript文档
 
技术图片

接口

接口用于检查对象是否适合于某个特定结构。通过接口定义,可以指定变量的特定组合,保证这样的这是组合会被一起使用。转换为JavaScript后,接口就消失了。接口存在的唯一目的就是在开发阶段为开发人员提供帮助。
 
下面的示例,定义了一个简单接口对函数的参数进行类型检查:
// Here we define our Food interface, its properties, and their types.
interface Food {
    name: string;
    calories: number;
}

// We tell our function to expect an object that fulfills the Food interface. 
// This way we know that the properties we need will always be available.
function speak(food: Food): void{
  console.log("Our " + food.name + " has " + food.calories + " calories.");
}

// We define an object that has all of the properties the Food interface expects.
// Notice that types will be inferred automatically.
var ice_cream = {
  name: "ice cream", 
  calories: 200
}

speak(ice_cream);
属性的顺序无关紧要,需要属性需要存在、类型正确。如部分缺失、类型错误或名称不对,编译器就会报错。
interface Food {
    name: string;
    calories: number;
}

function speak(food: Food): void{
  console.log("Our " + food.name + " has " + food.calories + " grams.");
}

// We‘ve made a deliberate mistake and name is misspelled as nmae.
var ice_cream = {
  nmae: "ice cream", 
  calories: 200
}

speak(ice_cream);
main.ts(16,7): error TS2345: Argument of type { nmae: string; calories: number; } 
is not assignable to parameter of type Food. 
Property name is missing in type { nmae: string; calories: number; }.
本文用于TypeScript初步介绍,将不对接口进行更详细的说明。关于接口,需要了解的内容比这里提到的要多得多,建议查看TypeScript文档
 
技术图片

构建大型应用程序的时候,许多开发人员都倾向于使用面向对象的编程风格,尤其是Java或C#等语言。TypeScript提供了一种与这些语言非常相似的类系统,包括继承、抽象类、接口实现、setters / getters等。
 
需要说明的是,最新的JavaScript更新(ECMAScript 2015)里,类是原生JS的一部分,可在不使用TypeScript的情况下在Javascript里使用类。两种实现非常相似,但有还是有所区别:TypeScript的类更为严格。
 
还是使用上面关于Food的场景,下面是一个简单的TypeScript类:
class Menu {
  // Our properties:
  // By default they are public, but can also be private or protected.
  items: Array<string>;  // The items in the menu, an array of strings.
  pages: number;         // How many pages will the menu be, a number.

  // A straightforward constructor. 
  constructor(item_list: Array<string>, total_pages: number) {
    // The this keyword is mandatory.
    this.items = item_list;    
    this.pages = total_pages;
  }

  // Methods
  list(): void {
    console.log("Our menu for today:");
    for(var i=0; i<this.items.length; i++) {
      console.log(this.items[i]);
    }
  }

} 

// Create a new instance of the Menu class.
var sundayMenu = new Menu(["pancakes","waffles","orange juice"], 1);

// Call the list method.
sundayMenu.list();
写过Java或C#的人都会觉得这种语法很熟悉。对于继承的语法大家应该也会有这种熟悉的感觉:
class HappyMeal extends Menu {
  // Properties are inherited

  // A new constructor has to be defined.
  constructor(item_list: Array<string>, total_pages: number) {
    // In this case we want the exact same constructor as the parent class (Menu), 
    // To automatically copy it we can call super() - a reference to the parent‘s constructor.
    super(item_list, total_pages);
  }

  // Just like the properties, methods are inherited from the parent.
  // However, we want to override the list() function so we redefine it.
  list(): void{
    console.log("Our special menu for children:");
    for(var i=0; i<this.items.length; i++) {
      console.log(this.items[i]);
    }

  }
}

// Create a new instance of the HappyMeal class.
var menu_for_children = new HappyMeal(["candy","drink","toy"], 1);

// This time the log message will begin with the special introduction.
menu_for_children.list();
更多了解TS中的类,可参阅此文档
 
技术图片

泛型

泛型允许同一个函数以模板形式接受不同类型参数。相比起来,使用泛型创建可重用的组件比使用any数据类型更方便,因为泛型保留了输入、输出变量的类型。
 
下面的示例代码接受一个输入参数并返回包含相同参数的数组。
// The <T> after the function name symbolizes that it‘s a generic function.
// When we call the function, every instance of T will be replaced with the actual provided type.

// Receives one argument of type T,
// Returns an array of type T.

function genericFunc<T>(argument: T): T[] {    
  var arrayOfT: T[] = [];    // Create empty array of type T.
  arrayOfT.push(argument);   // Push, now arrayOfT = [argument].
  return arrayOfT;
}

var arrayFromString = genericFunc<string>("beep");
console.log(arrayFromString[0]);         // "beep"
console.log(typeof arrayFromString[0])   // String

var arrayFromNumber = genericFunc(42);
console.log(arrayFromNumber[0]);         // 42
console.log(typeof arrayFromNumber[0])   // number
第一次调用此函数时,将类型设置为字符串。这个操作并非必须要做,因为编译器能够判断传递的参数类型,可以自动确定哪种类型最适合,第二次调用即是如此。虽然泛型的类型指定不是强制性的,但每次諷用者提供类型都是一种良好的编码习惯,因为有可能在更为复杂的情况下编译器无法判断正确的类型。
 
TypeScript文档包括一些更复杂的示例,包括泛型类、与接口组合等等。您查看这里找到这些示例。
 
技术图片

模块

大型应用程序的另一个重要概念是模块化。和单个10000行的代码文件相比,代码划分为许多可重用的小组件可以让项目更容易组织、代码可易于理解。
 
TypeScript引入了export和import模块的语法,但无法处理文件之间的实际连接。要启用外部模块,TS依赖于第三方库:浏览器应用程序为require.js,Node.js 为CommonJS。来看一个带有require.js的TypeScript模块的简单示例。
 
示例引入两个代码文件,一个文件export一个方法,另外一个文件import后调用此方法。
exporter.ts
var sayHi = function(): void {
    console.log("Hello!");
}

export = sayHi;
importer.ts
import sayHi = require(./exporter);
sayHi();
需要下载require.js并将其包含在脚本标记中- 在此处查看操作方法。最后一步是编译这两个.ts文件。和CommonJS不一样之处在于,需要添加一个额外的参数来告诉TypeScript我们正在为require.js(也称为AMD)构建模块。
tsc --module amd *.ts
TypeScript模块支持的内容很多,其它内容超出了本文范围。如想继续了解,请访问TS文档
 
技术图片

第三方的声明文件

使用为JavaScript设计的库时,我们需要使用声明文件以使该库可以与TypeScript兼容。声明文件的扩展名为.d.ts,其中包含有关库及其API的各种信息。
 
TypeScript声明文件通常是手工编写的,但也有可能要用到的库已经有一个由其他人创建的.d.ts文件。DefinitelyTyped是最大的公共存储库,包含超过一千个库的文件。还有一个流行的Node.js模块,用于管理TypeScript定义,称为Typings
 
如需自己编写声明文件,此指南将用于了解入门信息。
 
技术图片

TypeScript 2.0中的新功能

TypeScript仍在积极开发中,并且会不断发展。撰写本教程时(译注:原文发表于2016年),LTS版本是1.8.10,但Microsoft已经发布了TypeScript 2.0 Beta。可以用于公共测试,需要尝试的话:
npm install -g typescript @ beta
TypeScript 2.0引入了一些的新概念,如:
  • 非空类型标志,可防止某些变量将其值设置为nullundefined
  • 以通过npm install得到声明文件的改进的方式
  • 控制流类型分析,可捕获编译器遗漏的错误
  • 模块导出/导入语法中的一些创新
另一个期待已久的功能是控制async/await块中异步功能流的能力。在将来的2.1更新中应该可用。

进一步阅读

最初,官方文档中的信息量可能有点让人不知所措,但坚持阅读将获得很大的好处。本文作为介绍性文字,没有涵盖TypeScript文档中的所有章节。以下是一些我们跳过的、但更有帮助的概念:

最后

希望本文会对大家有所帮助,大家能喜欢这篇文章。
 原文参见:30分钟学会TypeScript

以上是关于30分钟学会TypeScript的主要内容,如果未能解决你的问题,请参考以下文章

10分钟学会TypeScript,总结TS的常用特性

grunt整合版30分钟学会使用grunt打包前端代码

(转)30 分钟学会 Flex 布局

grunt整合版30分钟学会使用grunt打包前端代码

小白30分钟学会网页采集基础教程

十分钟玩转TypeScript