这一篇主要梳理介绍一下TypeScript当中的一些基本语法,在认真看完本篇内容,你将会对TypeScript又一个基本的掌握,并能够使用TypeScript编写简单的ts语句。
一、类型声明
我们前面讲过,TypeScript对于JavaScript最显著的特征,就是为变量加上了类型声明。比如我们要定义一个string类型的变量foo,在JavaScript中我们只需要
var foo; // 或者
let foo;
但在TypeScript中我们定义一个变量,一般我们会写下
let foo: string;
可以看到在上述代码中,我们明显的发现在TypeScript中定义变量foo时,我们在变量标志符后添加了冒号+类型。没错这就是TypeScript类型声明的写法。
同样的我们也可以使用这样的方法来声明函数参数和函数返回值的类型,我们尝试一下:
function fun (num: number): string {
return String(num)
}
上述代码中,我们定义了一个函数fun,并且要求其传入一个number类型的参数num,执行体返回强制转换为string类型后的num,也就是说该函数fun最终的返回值类型为string。在TypeScript代码中,我们可以不用关注函数执行体内的运行逻辑,即可一眼看出该函数最终的返回值类型,这完全归功于TypeScript引入的类型声明。
当然需要注意的是,当TypeScript代码为某一变量已经进行了类型声明之后,我们再给该变量赋值不同类型的值,这将不被TypeScript允许,进而报错。例如:
let str: string = 123; // 报错
还需要注意的一点是:与JavaScript不同的是,在JavaScript中,当一个变量未被赋值时,是可以被读取并且返回undefined
;但在TypeScript中,变量只有被赋值之后才能使用,否则会报错。 例如:
let str: string;
console.log(str); // 报错
二、类型推断
我们之前讲过说TypeScript没有运行时,其运行完全依赖编译后的JavaScript代码的运行环境,那也就是说,TypeScript完全兼容JavaScript,因为其并不会改变JavaScript运行时的特性。换个说法讲,就是所有的JavaScript代码都应当是合法的TypeScript代码。
那么我们能不能像JavaScript中定义变量一样不实用类型声明,直接进行变量定义呢?答案是肯定的。我们现在尝试使用JavaScript常用语法在TypeScript文件中定义一个变量并尝试给其赋值:
let num = 123;
num = '123'; // 报错
我们看到在上述代码中,我们使用常规的JavaScript手段定义了一个变量num
并初始化其值为数值123
,没有问题,但当我们对该变量进行修改值时,我们试图将其赋值为字符串类型'123'
,TypeScript阻止了我们的非法操作。
我们在此例中并没有提前声明变量num
的类型,但在TypeScript中,编译器会通过我们对该变量的初始化赋值自动推断变量num
的类型为数值型,所以当我们试图修改其变量类型,则会被告知不允许。
同样的,TypeScript也可以推断一个函数的返回值类型。例如上文所写的函数案例,我们可以简写为:
function fun (num: number) {
return String(num)
}
在这里的代码中,我们并没有声明函数fun返回值的类型,但不用担心,TypeScript会自动推断这里返回的一定是string类型的值。正是因为TypeScript的类型推断,所以一般我们对于函数返回值的类型通常是省略不写的。
从这里可以看到,TypeScript的设计思想是,类型声明是可选的,你可以加,也可以不加。即使不加类型声明,依然是有效的TypeScript代码,只是这时不能保证TypeScript会正确推断出类型。
所以我们发现如果公司要求将以前的JavaScript项目改为TypeScript项目时,我们可以逐步地为老代码添加类型,即使有些代码没有添加,也不会无法运行,这并不影响。
三、值与类型
我们讲了这么多,可能会有部分读者看的一头雾水,我们想想初次拿到一份TypeScript代码时,映入脑海的第一个疑问,相信有不少同学会疑惑为什么通篇定义变量后面会有冒号加其他的不知所云的东西。我想大部分人阅读上面两段内容之后应该明白了其中的因果关系,如果你现在还不理解,那么我们来讲两个概念——值(value)、类型(type)。
在TypeScript中,“值”和“类型”是多对一出现的,也就是说每一个值在TypeScript代码中都对应一个类型,但不是一个类型只对应一个值。类型是针对值出现的,可以看成是值的一个元属性。
在TypeScript代码中,只涉及类型,不涉及值。
这句话初听有点晦涩难懂,但是我们思考一下,我们在写TypeScript代码时,其实本质是,我们在写JavaScript代码,并在JavaScript代码中添加了TypeScript额外的类型语法。而所有跟值相关的代码,即逻辑代码几乎全部都由JavaScript所处理,TypeScript所处理的只有类型。
所以我们说在TypeScript项目里面,其实存在两种代码,一种是底层的“值代码”,由JavaScript处理,另一种是上层的“类型代码”,由TypeScript处理。 此两者是可以分离的,事实上,在TypeScript的编译过程中,编译器所做的也只是把“类型代码”全部拿掉,然后保留JavaScript可运行的“值代码”。
四、TypeScript的编译(compile)
讲一下TypeScript的编译,我们前面讲TypeScript没有运行环境,其运行完全依赖JavaScript运行环境(即浏览器或Node.js),所以TypeScript项目想要运行,则必须先将代码转换为JavaScript代码,这个代码转换的过程,我们叫做“编译”。这个过程在Java或者C系列语言中比较常见。
TypeScript官方没有做运行环境,只提供编译器。编译时,会将类型声明和类型相关的代码全部删除,只留下能运行的JavaScript代码,并且不会改变JavaScript的运行结果。
因此,TypeScript的类型检查只是编译时的类型检查,而不是运行时的类型检查。一旦代码编译为JavaScript,运行时就不再检查类型了。
五、TypeScript的编译器——tsc
TypeScript官方提供的编译器叫做tsc,可以将TypeScript脚本编译成JavaScript脚本,所以本机想要编译TypeScript代码,必须先安装tsc。
tsc是一个npm模块,使用npm命令则可全局安装tsc
$ npm install -g typescript # 安装命令
$ tsc -v # 检查tsc是否安装成功 或者使用 tsc --version
# Version 5.4.2 控制台输出版本号则表示安装成功
tsc的其他常用命令
$ tsc -h # 输出帮助信息 或者使用 tsc --help
$ tsc --all # 查看全部完整的帮助信息
$ tsc app.ts # 编译ts文件脚本 该命令会将目标ts文件编译输出生成一个app.js文件脚本,在当前目录下
$ tsc app1.ts app2.ts app3.ts # 一次型编译多个ts文件脚本
# tsc 命令的其他参数
$ tsc app1.ts app2.ts --outFile app.js # 该命令可以将多个ts文件脚本编译生成一个js文件脚本app.js
$ tsc app.ts --outDir dist # 该命令指定编译生成的js文件脚本保存目录为当前目录下的dist文件下
$ tsc --target es2015 app.ts # 该命令指定编译后的js脚本文件符合es2015标准版本
需要注意的是,tsc编译器在施行错误的TypeScript文件脚本编译过程时,会在控制台报错提示,但tsc仍然会将TypeScript文件脚本编译成目标JavaScript文件脚本。 这是因为 TypeScript 团队认为,编译器的作用只是给出编译错误,至于怎么处理这些错误,那就是开发者自己的判断了。开发者更了解自己的代码,所以不管怎样,编译产物都会生成,让开发者决定下一步怎么处理。
当然如果希望编译过程一旦产生报错,便立刻停止编译,我们可以使用--noEmitOnError
参数进行控制,使用方法如下:
$ tsc --noEmitOnError app.ts
tsc还有一个--noEmit
参数,只检查类型是否正确,不生成JavaScript文件。
$ tsc --noEmit app.ts
六、tsconfig.json——tsc编译参数配置文件
这个文件在后面我们使用TypeScript开发项目时做工程化很有帮助。
TypeScript允许将tsc的编译参数,写在配置文件tsconfig.json
。只要当前目录有这个文件,tsc就会自动读取,所以运行时可以不写参数。
举个例子,比如我们要将下面一个tsc命令进行参数配置方式书写:
# tsc原命令形式
$ tsc app1.ts app2.ts --outFile dist/app.js
// tsconfig.json形式
{
"files": ["app1.ts", "app2.ts"],
"compilerOption": {
"outFile": "dist/app.js"
}
}
有了这个配置文件,我们运行编译器时,即可直接使用tsc命令而不带任何参数。
tsconfig.json
十分重要,后面会专门出文章进行介绍,感谢阅读。