什么是 TypeScript
TypeScript is JavaScript with syntax for types.(TypeScript 是带有类型语法的 JavaScript)
TypeScript最终还是会编译成javascript运行
类型系统
从 TypeScript 的名字就可以看出来,「类型」是其最核心的特性。
我们知道,JavaScript 是一门非常灵活的编程语言:
-
它没有类型约束,一个变量可能初始化时是字符串,过一会儿又被赋值为数字。
-
由于隐式类型转换的存在,有的变量的类型很难在运行前就确定。
-
基于原型的面向对象编程,使得原型上的属性或方法可以在运行时被修改。
-
函数是 JavaScript 中的一等公民,可以赋值给变量,也可以当作参数或返回值。
这种灵活性就像一把双刃剑,一方面使得 JavaScript 蓬勃发展,无所不能,从 2013 年开始就一直蝉联最普遍使用的编程语言排行榜冠军;另一方面也使得它的代码质量参差不齐,维护成本高,运行时错误多。
而 TypeScript 的类型系统,在很大程度上弥补了 JavaScript 的缺点。
TypeScript 是静态类型
类型系统按照「类型检查的时机」来分类,可以分为动态类型和静态类型。
动态类型是指在运行时才会进行类型检查,这种语言的类型错误往往会导致运行时错误。JavaScript 是一门解释型语言,没有编译阶段,所以它是动态类型,以下这段代码在运行时才会报错:
let foo = 1; foo.split(' '); // Uncaught TypeError: foo.split is not a function // 运行时会报错(foo.split 不是一个函数),造成线上 bug
静态类型是指编译阶段就能确定每个变量的类型,这种语言的类型错误往往会导致语法错误。TypeScript 在运行前需要先编译为 JavaScript,而在编译阶段就会进行类型检查,所以 TypeScript 是静态类型,这段 TypeScript 代码在编译阶段就会报错了:
let foo = 1; foo.split(' '); // Property 'split' does not exist on type 'number'. // 编译时会报错(数字没有 split 方法),无法通过编译
你可能会奇怪,这段 TypeScript 代码看上去和 JavaScript 没有什么区别呀。
没错!大部分 JavaScript 代码都只需要经过少量的修改(或者完全不用修改)就变成 TypeScript 代码,这得益于 TypeScript 强大的类型推论
,即使不去手动声明变量 foo
的类型,也能在变量初始化时自动推论出它是一个 number
类型。
完整的 TypeScript 代码是这样的:
let foo: number = 1; foo.split(' '); // Property 'split' does not exist on type 'number'. // 编译时会报错(数字没有 split 方法),无法通过编译
安装 TypeScript
TypeScript 的命令行工具安装方法如下:
npm install -g typescript
以上命令会在全局环境下安装 tsc
命令,安装完成之后,我们就可以在任何地方执行 tsc
命令了。
编译一个 TypeScript 文件很简单:
tsc hello.ts 编译指定文档 tsc 编译当前路径下所有.ts文件
我们约定使用 TypeScript 编写的文件以 .ts
为后缀,用 TypeScript 编写 React 时,以 .tsx
为后缀。
Hello TypeScript
我们从一个简单的例子开始。
将以下代码复制到 hello.ts
中:
function sayHello(person: string) { return 'Hello, ' + person; } let user = 'Tom'; console.log(sayHello(user));
然后执行
tsc hello.ts
这时候会生成一个编译好的文件 hello.js
:
function sayHello(person) { return 'Hello, ' + person; } var user = 'Tom'; console.log(sayHello(user));
在 TypeScript 中,我们使用 :
指定变量的类型,:
的前后有没有空格都可以。
上述例子中,我们用 :
指定 person
参数类型为 string
。但是编译为 js 之后,并没有什么检查的代码被插入进来。
这是因为 TypeScript 只会在编译时对类型进行静态检查,如果发现有错误,编译的时候就会报错。而在运行时,与普通的 JavaScript 文件一样,不会对类型进行检查。
如果我们需要保证运行时的参数类型,还是得手动对类型进行判断:
function sayHello(person: string) { if (typeof person === 'string') { return 'Hello, ' + person; } else { throw new Error('person is not a string'); } } let user = 'Tom'; console.log(sayHello(user));
下面尝试把这段代码编译一下:
function sayHello(person: string) { return 'Hello, ' + person; } let user = [0, 1, 2]; console.log(sayHello(user));
编辑器中会提示错误,编译的时候也会出错:
hello.ts:6:22 - error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
但是还是生成了 js 文件:
function sayHello(person) { return 'Hello, ' + person; } var user = [0, 1, 2]; console.log(sayHello(user));
这是因为 TypeScript 编译的时候即使报错了,还是会生成编译结果,我们仍然可以使用这个编译之后的文件。
如果要在报错的时候终止 js 文件的生成,可以在 tsconfig.json
中配置 noEmitOnError
即可。关于 tsconfig.json
,请参阅官方手册open in new window(中文版open in new window)
注意: 运行tsc时不能指定文件,否则会忽略tsconfig.json