浅谈 Typescript(一):什么是Typescript?

1,610 阅读4分钟

Typescript 为 JS 带来了类型能力,如今已被越来越多的大型前端项目选用。Typescript 的出现大大改善了开发体验,增强了代码的可维护性和稳定性。

本文你将看到:

  • Typescript 出现的意义
  • Typescript 的活动范围:类型声明空间和变量声明空间的区别和联系

1 什么是 Typescript

Typescript 是 Javascript 的超集。

Typescript 为 Javascript 增加类型能力,主要为了避免 JS 弱类型下产生的各种有意无意的问题。或者说,TS 用来限制 JS 的编写,就像一个 lint 一样。

Typescript 提供什么类型能力?

  • 在开发过程中,配合IDE,TS 能实时检查类型的合法性,还能基于类型给出更精准的自动补全等特征提升码字效率。
  • 在编译过程中,TS 仍然能做类型检查,再把 TS 代码编译成 JS 代码。

第一段代码

let name: string = 'henry';

这样一段代码,就是 TS 的基本玩法。name 变量在声明的同时,注解了 string 类型,从此只有字符串能赋值给 name。如果你给了其他类型,TS 既会在开发时提醒你,也会在编译时打断抛错。

2 类型声明空间

其实 TS 在变量声明的过程中,构建了另一个平行的类型声明空间。理解两个空间的隔离和联系,才能在各种杂乱的声明中保持清醒。

理解类型声明空间和变量声明空间

C779681B-E11B-4CC9-A505-8FD3B467E8E8 2.png

类型声明空间和变量声明空间是两个世界

  • 类型在其空间里可以互相引用赋值,但不能当变量
  • 变量在其空间里可以互相引用赋值,但不能当类型
  • 两个空间的声明甚至可以同名

但两者有交流的方式:

  • 在变量声明空间中,可以通过一些语法给变量注解类型,比如 const 变量: 类型
  • 在类型声明空间中,可以通过一些语法捕获变量的类型,比如 type 类型 = typeof 变量

在 TS 两个空间,这么多声明语法中:

  • 有些声明方式只声明变量,比如const C = 123;
  • 有些声明方式只声明类型,从声明那一刻起就只属于类型空间,比如:interface A {}type A = {}
  • 有些声明方式会同时声明类型和变量,比如:class A
  • 有些声明方式在声明类型的同时,还创建了变量空间的数据结构,比如enum

例子:

// 声明
class A {}	// 	在类型空间声明一个 A 类型;并在变量空间声明一个 A 变量
interface B {}	// 只在类型空间声明一个 B 类型
const C = 123;	// 只在变量空间声明一个 C 变量

let typeB: B;		// B可以当注解用
let varB = B;		// Error: 但不能当变量用

let typeC: C;		// Error: C不能当注解用
let varC = C;		// 但能当变量用

let varA = A;		// A 就可以当变量用也能当注解用
type typeA = A;

两个空间的编译

我们知道一个.ts文件是无法直接执行的,需要编译为对应的.js。然而.ts文件中同时有变量声明空间和类型声明空间的代码,那对于单个文件而言,从 TS 到 JS,要做的就是:

  • 把类型声明空间的部分择出来,剔除掉
  • 把变量声明空间的部分编译为 js

9554E89B-3731-42C7-AB1E-A3099AAFBA96.png

declare 环境声明

通常 TS 中,声明变量的同时注解类型,像这样:const foo: string = ''

TS 是可以兼容调用普通 JS 的。这种情况下没有类型声明,这也就意味着,你有一段只在「变量声明空间」干活的代码。那我如何创建对应的「类型声明」呢?如果仍通过 const Foo: string这种声明,很明显是语法错误了。比如下面对 jQuery 的引用。

// js 库中
const $ = jQuery();
// 我们的代码中
const $: any;	// Uncaught SyntaxError: Identifier '$' has already been declared

TypeScript 的设计目标之一是让你从现有的 JavaScript 库中安全、轻松的使用 TypeScript,你可以通过 TypeScript 声明文件来做到这一点。 你可以通过 declare 关键字,来告诉 TypeScript,你正在试图表述一个其他地方已经存在的代码(如:写在 JavaScript、CoffeeScript 或者是像浏览器和 Node.js 运行环境里的代码)

declare 用来定义已经声明的变量的类型,表明这句 TS 只用于在「类型声明空间」对「变量声明空间」中已存在的内容进行类型补充,不具有执行意义。

// js 库中
const $ = jQuery();
// 我们的代码中
declare const $: any;		// 只为了补充 $ 的类型,不会执行

事实上编译后 declare 这句就没了。

"use strict";
// js 库中
const $ = jQuery();

这样,「变量声明空间」和「类型声明空间」又对齐了。

小结

本篇我们从了解 TS 出发:

  • Typescript 提供了类型能力,提高开发效率,提升代码可维护性和稳定性
  • Typescript 开辟了和「变量声明空间」平行的「类型声明空间」,二者相互独立
  • 两个空间的内容,可以通过注解等行为互相关联
  • 所谓单文件编译也是剔除类型声明空间,保留变量声明空间的过程
  • declare 是一种专门为缺失类型的变量声明空间内容补充类型声明空间内容的方式

下一篇,我们会先关注「类型声明空间」下的表现,TS 如何提供丰富的类型来“降服”如此灵活的 JS 呢?