Typescript快速入门

TypeScript简介

什么是TypeScript?

简单地说TypeScript就是在JavaScript的基础上加上了类型检查。

TypeScript 与 JavaScript 有着不同寻常的关系。TypeScript 提供了 JavaScript 的所有功能,并在这些功能之上添加了一层: TypeScript 的类型系统。
例如,JavaScript 提供了诸如 string 和 number 这样的原始类型,但它不检查你在赋值时与类型是否匹配。TypeScript 提供了这样的功能。
这意味着你现有的运行良好的 JavaScript 代码也是 TypeScript 代码。TypeScript 的主要好处是,它可以检查代码中的意外行为,从而降低出现错误的机会。
(摘抄自:https://www.typescriptlang.org/zh/docs/handbook/typescript-in-5-minutes.html)

TypeScript安装

安装TypeScript需要用npm命令,而npm依赖于Node.js,因此首先得安装Node.js。

Node.js发布于2009年5月,实质是对Chrome V8引擎进行封装。可以在https://nodejs.org官网上下载最新的版本。
在这里插入图片描述
Node.js安装很简单,下载之后,按照向导一步一步根据默认配置操作即可,安装完成后,验证下是否安装成功。

在命令行工具中输入“node -v”和“npm -v”查看是否安装成功,如果安装成功就会显示版本号。
在这里插入图片描述
安装完npm之后,在命令行工具界面中输入命令“npm install -g typescript”全局安装TypeScript,稍等片刻,等待安装完成后,用命令tsc -v查看其版本号来验证是否安装成功。
在这里插入图片描述

第一行TypeScript代码

新建一个hi.ts文件,代码如下:

function hi(msg: string) : string {
    return "hi " + msg
}

console.log(hi('days'))

用命令 tsc *.ts 编译TypeScript代码,会在同一个目录下生成一个js文件。

tsc hi.ts

编译后的 hi.js JavaScript代码

function hi(msg) {
    return "hi " + msg;
}
console.log(hi('days'));

我们可以看到上述TypeScript必须给变量指定类型msg: string,而JavaScript代码的变量是不用指定类型的。

这是TypeScript作为一门静态语言和JavaScript作为一门动态语言最大的区别之一:

  • 静态语言是在编译时确定变量的数据类型的语言,需要声明变量的类型,不能随意改变。(TypeScript)
  • 动态语言是在运行时确定变量的数据类型的语言,不需要声明变量的类型,可以根据赋值改变。(JavaScript)

静态语言和动态语言都有各自的优点:

  • 静态语言可以在编译阶段发现错误和优化代码,提高程序的效率和安全性。
  • 动态语言可以在运行时动态改变程序的结构和功能,提高程序的灵活性和表达力。

静态语言可以在编译阶段发现错误和优化代码,这有什么好处呢?

我们来看一个JavaScript的例子:

if (1 < x < 3) {
  // x是 *任何* 值都为真!
}

为什么这个表达式永远为真呢?

这是因为 JavaScript 的比较运算符是从左到右结合的,所以 if (1 < x < 3) 实际上相当于 if ((1 < x) < 3),先比较 1 和 x 的大小,然后再比较结果和 3 的大小。

而(1 < x)的结果只能是 true 或 false,它们在 JavaScript 中会被转换成数字 1 或 0,所以无论 x 是什么值,if (1 < x < 3) 都会转换成if ((0或者1) < 3),结果永远是 true。

如果想要判断 x 是否在 1 和 3 之间,正确的写法是 if (x > 1 && x < 3),使用逻辑与运算符 && 来连接两个条件。

TypeScript可以在代码运行之前就能发现这样的错误:

在这里插入图片描述
如果我们是在编写一个大型的项目,有成千上万行代码,这些奇怪的错误不及时发现,就会造成严重的后果。所以TypeScript就是为了适应大型项目的开发的。

TypeScript的主要特点

编译和擦除类型

TypeScript的类型仅仅是为了在编译的时候检查用的,一旦TypeScript的编译器完成了检查代码的工作,它就会擦除类型最终生成“已编译”的JavaScript代码。

类型注解并不属于 JavaScript(或者专业上所说的 ECMAScript)的内容,所以没有任何浏览器或者运行时能够直接执行不经处理的 TypeScript 代码。

这也是为什么 TypeScript 首先需要一个编译器,因为它需要经过编译,才能去除或者转换TypeScript独有的代码,从而让这些代码可以在浏览器上运行。

这意味着一旦您的代码被编译,生成的普通JavaScript代码便没有类型信息。

TypeScript代码最终是编译成JavaScript代码运行的。

这意味着,如果将代码从JavaScript迁移到TypeScript ,即使TypeScript认为代码有类型错误,也可以保证以相同的方式运行。

保持与JavaScript运行时行为相同是TypeScript的基本特性,你可以轻松地在两种语言之间转换,而不必担心一些细微差别可能会使程序抛出异常而停止工作。

类型推断

TypeScript 可以识别 JavaScript 语言,在许多情况下可以推断类型。

在创建变量并将其赋值给特定值时,TypeScript 可以感知其数据类型,例如 let helloWorld 赋值了字符串,那么 TypeScript 就可以推断出变量 helloWorld 是 string 类型。
在这里插入图片描述

定义类型

你可以使用 interface 关键字声明显式地描述此对象的内部数据的类型:

interface User {
  name: string;
  id: number;
}

然后你可以声明一个符合此接口(interface)的 JavaScript 对象,在变量声明后使用像 : TypeName 这样的语法:

interface User {
  name: string;
  id: number;
}
// ---分割线---
const user: User = {
  name: "Hayes",
  id: 0,
};

如果提供的数据类型与提供的接口不匹配,TypeScript 会警告:
在这里插入图片描述
name在接口中定义成了string类型,而在user对象中赋值为1,就会抛出类型不匹配的警告。

我们还可以定义一个带构造方法的类和接口:

interface User {
  name: string;
  id: number;
}
 
class UserAccount {
  name: string;
  id: number;
 
  constructor(name: string, id: number) {
    this.name = name;
    this.id = id;
  }
}
 
const user: User = new UserAccount("唐三", 1);

联合类型

联合类型使用管道符号(|)表示一个值可以是多种类型之一。这在函数参数和返回值中非常有用,可以让你处理具有不同类型的输入和输出。

例如:

type StringOrNumber = string | number;

function printValue(value: StringOrNumber) {
  console.log(value);
}

printValue("hello"); // 输出 "hello"
printValue(42); // 输出 42

在这个例子中,我们创建了一个名为 StringOrNumber 的联合类型,表示值可以是 string 或 number 类型。我们的 printValue 函数接受一个 StringOrNumber 类型的参数,并将其打印到控制台。

泛型

TypeScript 的泛型是一种编程技术,允许你在定义函数、接口和类时使用类型参数,从而实现类型安全的代码重用。泛型在编译时保留类型信息,这有助于捕获类型错误,并提高代码的可维护性和可读性。

在 TypeScript 中,泛型使用尖括号(<>)来表示类型参数。例如,Array 表示一个元素类型为 T 的数组,其中 T 是类型参数。

泛型函数:

假设我们要创建一个函数,将一个数组中的所有元素都包装在一个对象中,如 {value: element}。我们可以使用泛型来实现这个函数,以便它适用于不同类型的数组:

function wrapInObject<T>(array: T[]) {
    return array.map((element) => ({value: element}))
}

console.log(wrapInObject([1,2,3]))  // 输出[ { value: 1 }, { value: 2 }, { value: 3 } ]
console.log(wrapInObject(['a','b','c'])) // 输出[ { value: 'a' }, { value: 'b' }, { value: 'c' } ]

这里,T 是一个类型变量,用于表示元素的类型。当我们实际调用 wrapInObject 时,TypeScript 会根据传入的数组类型推断出 T 的具体类型。

泛型类:

泛型同样可以应用于类。

例如,我们创建一个简单的栈类:

class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }
}

const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
console.log(numberStack.pop()); // 输出:2

const stringStack = new Stack<string>();
stringStack.push("a");
stringStack.push("b");
console.log(stringStack.pop()); // 输出:"b"

在这个例子中,我们定义了一个包含一个类型参数 T 的泛型类 Stack。T 表示栈中元素的类型。当我们创建 Stack 的实例时,需要为 T 指定具体的类型。

接口

TypeScript 的接口(Interface)是一种定义对象结构和约束的方法。接口可以描述对象的形状(即属性和方法),并为类和函数定义约定。通过接口,我们可以确保代码符合预期的结构和行为,提高代码的可读性和可维护性。

接口主要有以下几个用途:

描述对象的形状:

接口可以用来描述对象应该具有哪些属性和方法。这使得我们可以在编写代码时获得类型检查和智能提示,从而减少出错的可能性。

例如,我们可以定义一个描述用户信息的接口:

interface User {
  id: number;
  name: string;
  age: number;
}

function printUserInfo(user: User): void {
  console.log(`ID: ${user.id}, Name: ${user.name}, Age: ${user.age}`);
}

const user: User = { id: 1, name: "Alice", age: 30 };
printUserInfo(user);

在这个例子中,User 接口定义了用户信息应具有的属性。printUserInfo 函数接受一个 User 类型的参数,这样我们可以确保传递给该函数的对象具有正确的结构。

描述函数类型:

接口也可以用来描述函数的类型。这包括函数的参数类型和返回值类型。

例如,我们可以定义一个用于比较两个值的接口:

interface Comparator<T> {
  (a: T, b: T): number;
}

const numberComparator: Comparator<number> = (a, b) => {
  return a - b;
};

const stringLengthComparator: Comparator<string> = (a, b) => {
  return a.length - b.length;
};

在这个例子中,Comparator 接口定义了一个泛型函数类型,用于比较两个值。我们创建了两个不同类型的比较器:一个用于比较数字,另一个用于比较字符串的长度。

实现接口的类:

类可以实现接口,以确保遵循特定的约定。当一个类实现了一个接口时,TypeScript 会检查该类是否具有接口所要求的属性和方法。

例如,我们可以定义一个表示几何形状的接口和一个实现该接口的类:

interface Shape {
  area(): number;
  perimeter(): number;
}

class Rectangle implements Shape {
  constructor(private width: number, private height: number) {}

  area(): number {
    return this.width * this.height;
  }

  perimeter(): number {
    return 2 * (this.width + this.height);
  }
}

const rectangle = new Rectangle(10, 5);
console.log(rectangle.area()); // 输出:50
console.log(rectangle.perimeter()); // 输出:30

在这个例子中,Shape 接口定义了几何形状应具有的方法。Rectangle 类实现了 Shape 接口,确保了它具有正确的方法。

通过使用接口,我们可以确保对象、函数和类具有预期的结构和行为。

运行 .ts 文件的方法

方法一:先将 .ts 文件编译成 .js,再运行 .js 文件

  1. 安装 typescript
npm install -g typescript // 如果已经安装过请忽略这步
  1. 将 .ts 文件编译成 .js 文件,例如文件名为test.ts
tsc test.ts // 会在当前目录下生成对应的 test.js 文件
  1. 运行 .js 文件
node test.js

方法二:通过 ts-node 直接运行 .ts 文件

  1. 安装 typescript、ts-node
npm install -g typescript ts-node
  1. 直接运行 .ts 文件
ts-node test.ts

方法三:在线运行

在浏览器打开:https://www.typescriptlang.org/play
可以在线运行:
在这里插入图片描述

总结

TypeScript 是 JavaScript 的一个超集,它在 JavaScript 的基础上引入了一些额外的特性,旨在帮助开发者编写更健壮、易于维护的代码。下面是 TypeScript 的一些主要特点:

  • 静态类型检查:TypeScript 提供了静态类型检查,这意味着在代码运行之前,TypeScript 就能检查代码中的类型错误。这有助于及时发现和修复潜在的问题,降低运行时出现错误的风险。
  • 类型推断:TypeScript 能够根据变量的使用和赋值来推断其类型。这样,在许多情况下,你无需显式地为变量指定类型,TypeScript 会自动为你推断出正确的类型。
  • 泛型:TypeScript 支持泛型编程,允许你创建可以适用于多种类型的函数、类和接口。泛型有助于提高代码的复用性,同时保持类型安全。
  • 接口:TypeScript 的接口可以用来描述对象的形状(即属性和方法),以及定义类和函数的约定。接口可以帮助确保代码符合预期的结构和行为。
  • 类和面向对象编程:TypeScript 提供了对类和面向对象编程特性的完整支持,包括继承、封装、抽象类和访问修饰符等。这有助于组织和管理大型代码库。
  • 装饰器:TypeScript 支持装饰器,这是一种元编程特性,允许你修改或扩展类、属性、方法和参数的行为。装饰器有助于编写可重用和可组合的代码
  • 丰富的工具支持:TypeScript 可以与许多流行的代码编辑器(如 Visual Studio Code)集成,提供智能感知、自动补全、重构等功能。这有助于提高开发者的工作效率。
  • 良好的生态系统:TypeScript 可以与许多现代前端框架(如 Angular、React 和 Vue.js)无缝集成,并拥有大量的类型定义文件,使得你可以轻松地为第三方库添加类型支持。

总之,TypeScript 的特点包括静态类型检查、类型推断、泛型、接口、面向对象编程支持、装饰器以及丰富的工具和生态系统支持。这些特性使得 TypeScript 成为开发大型、可维护的 JavaScript 项目的理想选择。

参考资料:https://www.typescriptlang.org/zh/docs/handbook/typescript-from-scratch.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值