TypeScript速成教程

发布于1/16/2020 来自:「前端知否」微信公众号

Typescript是javascript的类型化超集,旨在简化大型javascript应用程序的开发。 Typescript添加了诸如类,泛型,接口和静态类型之类的通用概念,并允许开发人员使用诸如静态检查和代码重构之类的工具。

为什么要关注TypeScript:

为什么应该首先使用Typescript。下边是JavaScript开发人员应考虑学习Typescript的一些原因。

静态类型:

Javascript是动态类型的,这意味着它直到运行时实例化它之前都不知道变量的类型,这可能会导致项目中的问题和错误。 Typescript在Javascript中添加了静态类型支持,可解决由于正确使用变量类型而导致的错误。您仍然可以完全控制键入代码的严格程度,甚至根本不使用类型。

更好的IDE支持

Typescript优于Javascript的最大优势之一是对IDE的强大支持,其中包括Intellisense,来自Typescript编译器的实时信息,调试等。还有一些很棒的扩展,可以进一步提升您的Typescript开发经验。

访问新的ECMAScript功能

使用Typescript,您可以访问最新的ECMAScript功能,并将其转录为您选择的ECMAScript目标。这意味着您可以使用最新工具来开发应用程序,而不必担心浏览器支持。

什么时候应该使用它:

到现在为止,我们应该知道Typescript为什么有用,并且可以在哪里改善我们的开发经验。但这并不是万能的解决方案,当然也不能阻止您自己编写糟糕的代码。因此,让我们看一下您绝对应该在哪里使用Typescript。

当您拥有大型代码库时:

Typescript是大型代码库的重要补充,因为它可以帮助您避免许多常见错误。如果有更多的开发人员在一个项目上工作,这尤其适用。
当您和您的团队已经知道静态类型的语言时:

使用Typescript的另一个明显情况是,当您和您的团队已经知道Java和C#等静态类型的语言并且不想更改为编写Javascript时。

安装:

要安装TypeScript,我们只需要使用npm软件包管理器安装它并创建一个新的TypeScript文件。

npm install -g typescript

安装后,我们可以继续查看打字稿为我们提供的语法和功能。

类型:

现在,让我们看一下Typescript中对我们可用的类型。

Number:
Typescript中的所有数字均为浮点值。它们都获得数字类型,包括二进制和十六进制值。

let num: number = 0.222;
let hex: number = 0xbeef;
let bin: number = 0b0010;

String:
与其他语言一样,Typescript使用String数据类型保存文本数据。

let str: string = 'Hello World!';

您还可以使用多行字符串并通过用反引号将字符串括起来来嵌入表达式``

let multiStr: string = `A simple multiline string!`

let expression = 'A new expression'

let expressionStr: string = `Expression str: ${ expression }`

Boolean:
Typescript还支持所有最基本的数据类型,布尔值,只能为true或false。

let boolFalse: boolean = false;
let boolTrue: boolean = true;

分配类型:

现在我们有了基本的数据类型,接下来我们来看一下如何在Typescript中分配类型。基本上,您只需要在名称和冒号后面写上变量的类型。

单一类型:

这是一个将String数据类型分配给变量的示例:

let str: string = 'Hello World'

所有数据类型都一样。

多种类型

您还可以使用 | 为变量分配多个数据类型。

let multitypeVar: string | number = 'String'

multitypeVar = 20

在这里,我们使用 | 为变量分配两种类型。现在我们可以在其中存储字符串和数字了。


检查类型:

现在让我们看看如何检查变量的类型是否正确。我们有多种选择,但是这里我只显示两个最常用的。

Typeof:

typeof命令仅了解基本数据类型。这意味着它只能检查变量是否是我们上面定义的数据类型之一。

let str: string = 'Hello World!'

if (typeof str === number){

console.log('Str is a number')

} else {

console.log('Str is not a number')

}

在此示例中,我们创建一个String变量,并使用typeof命令检查str是否为Number类型(始终为false)。然后我们打印是否为数字。

Instanceof:

instanceof运算符与typeof几乎相同,除了它还可以检查javascript尚未定义的自定义类型。

class Human { 
name: string;

constructor(data: string) {
this.name = data;
}
}

let human = new Human('Gabriel')

if (human instanceof Human) {
console.log(`${human.name} is a human`)
}

在这里,我们创建一个自定义类型,我们将在本文后面的内容中进行讨论,然后创建一个实例。之后,我们检查它是否确实是类型为Human的变量,如果是,则在控制台中打印。

类型断言:

有时我们还需要将变量转换为特定的数据类型。当您分配了任何通用类型并且要使用具体类型的函数时,通常会发生这种情况。

有多个选项可以解决此问题,但是在这里我仅分享其中两个。

As关键字:

我们可以在变量名称后使用as关键字轻松地对变量进行强制转换,然后使用数据类型。

let str: any = 'I am a String'

let strLength = (str as string).length

在这里,我们将str变量强制转换为String,以便可以使用length参数。 (如果您的TSLINT设置允许,甚至可以在不进行强制转换的情况下工作)

<>运算符:

我们还可以使用<>运算符,其作用与关键字完全相同,只是语法有所不同。

let str: any = 'I am a String'

let strLength = (<string>str).length

该代码块具有与上面的代码块完全相同的功能。它仅在语法方面有所不同。

数组:

Typescript中的数组是相同对象的集合,可以用两种不同的方式创建。

创建数组

使用[]:

我们可以通过写入类型后跟 [] 表示对象是数组来定义对象的数组。

let strings: string[] = ['Hello', 'World', '!']

在此示例中,我们创建一个String数组,其中包含三个不同的String值。

使用通用数组类型

我们还可以通过编写Array <Type>来使用泛型类型定义数组。

let numbers: Array<number> = [1, 2, 3, 4, 5]

在这里,我们创建一个数字数组,其中包含5个不同的数字值。

多类型数组:

此外,我们还可以使用 | 将多个类型分配给单个数组。

let stringsAndNumbers: (string | number)[] = ['Age', 20]

在此示例中,我们创建了一个可以容纳字符串和数字值的数组。

多维数组

Typescript还允许我们定义多维数组,这意味着我们可以将一个数组保存在另一个数组中。我们可以通过使用多个[]运算符来创建多维数组。

let numbersArray: number[][] = [[1,2,3,4,5], [6,7,8,9,10]]

在这里,我们创建一个包含另一个数字数组的数组。

元组:

Tupels基本上就像一个数组,但是和数组有一个关键的区别。我们可以定义在每个位置上可以存储的数据类型。这意味着,我们可以通过枚举方括号内的类型来强制执行每个索引位置上对应的类型。

let exampleTuple: [number, string] = [20, 'https://zhaima.tech'];

在此示例中,我们创建了一个简单的元组,其中索引0上的数字和索引1上的字符串。这意味着,如果我们尝试在该索引上放置另一个数据类型,则将引发错误。

下边是无效的元组的示例:

const exampleTuple: [string, number] = [20, 'https://google.com'];

枚举:

与大多数其他面向对象的编程语言一样,Typescript中的枚举使我们能够定义一组命名常量。 Typescript还提供了数字枚举和基于字符串的枚举。使用enum关键字定义Typescript中的枚举。

Numeric:

首先,我们将看一下将键值与索引匹配的数字枚举。

enum State{
Playing = 0,
Paused = 1,
Stopped = 2
}

上面,我们定义了一个数字枚举,其中,Playing初始化为0,Paused初始化为1,依此类推。

enum State{
Playing,
Paused,
Stopped
}

我们还可以将初始化程序保留为空,并且Typescript会自动从零开始对其进行索引。

String:

在Typescript中定义String枚举很容易-我们只需要使用String初始化值即可。

enum State{
Playing = 'PLAYING',
Paused = 'PAUSED',
Stopped = 'STOPPED'
}

在这里,我们通过用String初始化状态来定义String枚举。

Objects:

Typescript中的对象是一个实例,其中包含一组键值对。这些值可以是变量,数组甚至函数。它也被视为代表非原始类型的数据类型。
我们可以使用花括号创建对象。

const human = {
firstName: 'Frank',
age: 32,
height: 185
};

在这里,我们创建一个具有三个不同键值对的人类对象。

我们还可以向我们的对象添加函数:

const human = {
firstName: 'Frank',

age: 32,

height: 185,

greet: function(){
console.log("Greetings stranger!")
}
};

自定义类型:

Typescript还使我们能够定义称为别名的自定义类型,以便以后使用。要创建自定义类型,我们只需要使用type关键字并定义我们的类型。

type Human = {firstName: string, age: number, height: number}

在此示例中,我们定义了一个自定义类型,其名称为Human和三个属性。现在让我们看看如何创建这种类型的对象。

const human: Human = {firstName: ‘Franz’, age: 32, height: 185}

在这里,我们创建自定义类型的实例并设置所需的属性。

函数参数和返回类型:

Typescript使我们能够设置函数参数的类型和返回类型。现在,让我们看一下使用Typescript定义函数的语法。

function printState(state: State): void {

console.log(`The song state is ${state}`)

}

function add(num1: number, num2: number): number {

return num1 + num2

}

在这里,我们有两个示例函数,它们都具有定义类型的参数。我们还看到,我们在右括号后面定义了返回类型。

现在我们可以像普通的javascript一样调用函数,但是编译器将检查是否为函数提供正确的参数。

add(2, 5)
add(1) // Error to few parameters
add(5, '2') // Error the second argument must be type number

可选属性:
Typescript还允许我们为函数定义可选属性。这个可以通过 ? 操作符做到。这是一个简单的示例:

function printName(firstName: string, lastName?: string) {
if (lastName) {
console.log(`Firstname: ${firstName}, Lastname: ${lastName}`);
} else {
console.log(`Firstname: ${firstName}`);
}
}

在此示例中,lastName是可选参数,这意味着当不提供调用函数的编译器时,不会从编译器中获取错误。

printName('Gabriel', 'Tanner')
printName('Gabriel')

这意味着这两种情况都将被视为正确。

默认值:

我们可以用来使属性成为可选属性的第二种方法是为其分配默认值。我们可以通过直接在函数的开头分配值来实现。

function printName(firstName: string, lastName: string = 'Tanner') {
console.log(`Firstname: ${firstName}, Lastname: ${lastName}`);
}

在此示例中,我们为lastName分配了默认值,这意味着我们不必在每次调用该函数时都提供它。

接口:

Typescript中的接口用于与我们的代码以及项目外部的代码定义合同。接口仅包含我们的方法和属性的声明,但不实现它们。实现方法和属性是实现接口的类的责任。

让我们看一个使这些语句更清楚的示例:

interface Person {
name: string
}

const person: Person = {name: 'Gabriel'}

const person2: Person = {names: 'Gabriel'} // is not assignable to type Person

在这里,我们创建一个具有一个属性的接口,该属性在实现接口时需要实现。这就是第二个人变量会引发错误的原因。

可选属性:

在Typescript中,不需要接口的所有属性。也可以使用?将属性设置为可选。属性名称后的运算符。

interface Person {
name: string
age?: number
}

const person: Person = {name: 'Frank', age: 28}

const person2: Person = {name: 'Gabriel'}

在这里,我们创建一个具有一个普通属性和一个可选属性的接口,该属性是使用?定义的。这就是上边两个person都有效的原因。

只读属性:

我们接口的某些属性也应仅在首次创建对象时进行修改。我们可以通过在属性名称之前放置readonly关键字来指定此功能。

interface Person {
name: string
readonly id: number
age?: number
}

const person: Person = {name: 'Gabriel', id: 3127831827}

person.id = 200 // Cannot assign to id because it is readonly

在此示例中,id属性是只读的,并且在创建对象后无法更改。

Barrels:

Barrels允许我们在一个更方便的模块中汇总几个导出模块。

我们只需要创建一个新文件即可导出项目的多个模块。比如index.ts:

export * from './person';
export * from './animal';
export * from './human';

这样做之后,我们可以使用一个方便的import语句导入所有这些模块。

import { Person, Animal, Human } from 'index';

泛型:

泛型允许我们创建与多种类型(而不是单个类型)兼容的组件。这有助于我们使组件“开放”并可重用。

现在,您可能想知道为什么我们不仅仅使用任何一种类型来为我们的组件接受一个以上的类型。让我们看一个例子,以更好地了解情况。

我们需要一个简单的假函数,该函数返回传递给它的参数。

function dummyFun(arg: any): any {
return arg;
}

尽管任何一种都是通用的,因为它接受所有类型的参数,但有一个很大的区别。我们正在丢失有关函数传递和返回的类型的信息。

因此,让我们来看看如何接受所​​有类型,同时又知道返回的类型。

function dummyFun<T>(arg: T): T {
return arg
}

在这里,我们使用了通用参数T,因此我们可以捕获变量类型并在以后使用它。我们还将它用作返回参数,这使我们在检查代码时可以看到相应的类型。

访问修饰符:

访问修饰符控制我们类成员的可访问性。 Typescript支持三个访问修饰符-公共,私有和受保护。

Public:

公开成员可以在任何地方不受任何限制。这也是标准修饰符,这意味着您不需要在变量前面加上public关键字。

Private:

只能在定义的类中访问私有成员。

Protected:

受保护的成员只能在定义的类和每个子类中访问。

TSLINT:

TSLINT是Typescript的标准linter,可以帮助我们编写干净,可维护和可读的代码。可以使用我们自己的棉绒规则,配置和格式化程序进行自定义。

安装:

首先,我们需要安装typescript和tslint,我们可以在本地或全局安装:

npm install tslint typescript --save-dev
npm install tslint typescript -g

之后,我们可以使用TSLINT CLI初始化项目中的TSLINT。

tslint --init

现在我们有了tslint.json文件,可以开始配置规则了。

配置:

TSLINT允许用于配置我们自己的规则和自定义我们的代码外观。默认情况下,tslint.json文件如下所示,并且仅使用默认规则。

{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {},
"rules": {},
"rulesDirectory": []
}

我们还可以向rules对象中添加其他规则。

"rules": {
"no-unnecessary-type-assertion": true,
"array-type": [true, "array"],
"no-double-space": true,
"no-var-keyword": true,
"semicolon": [true, "always", "ignore-bound-class-methods"]
},

有关所有可用规则的​​概述,请查看官方文档

最后

希望本文能帮助您了解Typescript的基础知识以及如何在项目中使用它。