JavaScript为弱引用类型语言,在声明变量时不需要声明变量类型,同时在声明后的操作当中也可以随意更改变量类型。而这种情况在类似于Java等强引用类型语言当中是不允许的。
TypeScript是JavaScript的超集,这意味着ts在兼容js所有语法的同时,对js进行了拓展,其中拓展的一步分就是在引用类型上变为了强引用类型语言,ts的出现一定程度上弥补了js作为一门编程语言不够严谨的地方,当然可能较为宽松的语法是js的一大特色,但在代码运行上来讲,很多时候这并非好事。ts能够在使用中通过一些额外的信息使代码更加健壮,在编写过程中一旦代码在ts中报错或者警告我们就知道这里可能会存在隐患。有点类似于我们ES6当中的eslint,都属于通过给我们编写的代码添加一定的约束来提高代码的健壮性,让我们尽量在开发过程中不要出错。但ts的价值远高于此,它能够使js的语法和功能更加规范和完善,形成一整套体系。
使用前第一件事是全局安装ts:安装前确认nodejs环境安装正确
npm install typescript -g
或者爱好使用yarn的话也可以
yarn global add typescript
安装完成后可以新建.ts为后缀的文件,编写ts代码。但要注意一点是写完之后要运行如下命令把代码解析成js才可以运行:
举例:
tsc 当前目录/当前文件名.ts --outFile 输出目录/新文件名.js
这样操作的问题是他每次运行命令都只会解析当前的代码,也就是说如果在开发过程中你每当作了修改就需要不断运行这段命令。
当然如果你嫌麻烦,不想每次更新写完代码都要重新运行命令进行编译,也可以运行如下命令实时解析ts代码:
tsc 当前文件夹目录/* --outDir 输出文件夹目录
也可以更加规范,方便开发过程中配置,先运行:
tsc --init
这个时候当前目录下就会出现tsconfig.json文件来进行具体的ts开发过程中的配置了。
比如上面的outDir命令就可以在文件当中找到,解开注释并把目录改成需要的目录就可以了。
其他功能这里就先不一一列举了。
解开outDir的注释后,我们只需要运行如下命令就可以按照我们tsconfig.json文件的配置进行ts文件的实时解析了。
tsc --watch
ts通常情况下在变量声明和引用不规范时会直接在控制台报错,这也是很多js开发者使用ts的第一个痛点:不熟悉变量如何声明。
1.string,number,boolean类型:
let param:string = "字符串";//string类型
let param:number = 1;//number类型
let param:boolean = true;//boolean类型
2.array类型:
数组属于复合数据类型,除了array本身的数据类型外,还要对内部每一个元素的类型进行声明。(当然在实际操作中数组内部元素的类型可能会比较复杂,并未简单数据类型,这种情况放在 5.any当中来讲)
//方法一:(数组范型)
let array:Array<number> //声明变量类型为数组,且内部的每一个元素都为number
array = [1, 2, 3]
//方法二:
let array:number[] //声明变量类型为数组,且内部的每一个元素都为number
array = [1, 2, 3]
3.Tuple元组:
元组类型类似于数组,并可以定义数组类型里的每一个元素的类型。数组声明时要统一规定内部每一个元素的类型,而元组声明时可以把每一个元素声明为不同类型。
let tuple:[number, string];
tuple = [1, "hello"]
//ps:ts是不支持越界访问的,比如当上面声明的tuple只有两个元素时,如果你访问除这两个元素之外的其他值的时候ts内部将直接报错。
console.log(tuple[3]) //ts终端报错,编译为js后会输出undefined。
4.枚举类型:
枚举这种类型在js中比较陌生,有点类似却又不同于js当中的类。也如同类一样,在js当中一开始是没有类这种类型的,我们在使用中都是用构造函数来替代的。但诸如Java等主流的面向对象的语言很多都是有类的,所以在ES6当中js也引入了类的概念。而枚举在ts当中的引入也是同样的道理。
//枚举类型用enum声明
enum Color {
Red, Yellow, Blue
}
//访问
let r: Color = Color.Red;
console.log(r) // 0
//枚举类型的赋值
enum Color {
Red = 2, Yellow = 4, Blue = 6
}
//访问
let colorName:string = Color[6]
console.log(colorName) //Blue
5.any类型:自动类型推断
这里很多用户在使用ts的过程中并未声明变量,但依然没有报错。这是因为在变量刚刚声明的过程中ts自动进行变量类型检测,声明和使用的过程中如果变量类型保持一致,就不会报错。但如果在使用过程中修改了变量类型,则会直接报错。
这里还要注意一点就是我们的浏览器能够运行的是js,而非ts,所以显然我们暂时也没有必要担心ts会取代js地位的问题。ts是在我们开发过程中使用的语言,运行时需要编译成js才能够被浏览器或node执行。也正因为其最终会被编译为js,所以在使用ts的过程中即使出现变量声明的错误,最终也不会影响代码的执行。但这就失去了我们使用ts的意义。
//自动类型推断
let param = 1; //直接声明不报错
let param = 1;
param = '1'; //报错: Type "1" is not assignable to type 'number'.ts
//自动类型推断
//示例1
let param:number[]; //当我们声明一个数组类型时
param.substr() //报错,因为substr是字符串方法,当我们声明数组时就默认当前变量只有数组相关方法,其他情况下可以举一反三
很多应用环境中,我们在声明变量的时候可能并不确定这个变量是什么类型,尤其是在复合数据类型当中,这个时候我们可以把这个变量类型声明成:any
//any类型
let param:any = 1;
param = '1';
param = true;
//都不会报错
//并且当变量声明为any时,这个变量就不会出现上方示例1当中的问题。
//当数组元素类型不确定时
let list: any[] = [1, '1', true];
6.void类型:
提到void,js当中我们可以进行这种操作javascript:void(0)用来阻止默认事件。
在ts中void则表示无返回值,与any类型相反,即任何类型都不可以。
//我们可以这么定义一个函数
function func():void { //此时这个函数不可以有任何返回值
return //可以return空或不return,不报错。
}
//但不能return任何值
function func():void { //此时这个函数不可以有任何返回值
return 1 //报错
}
//或者可以这样声明
let u:void = undefined; //总之就是不可以返回任何存在的值
7.联合类型:
很多时候一个变量可能会出现几种确定的变量类型,这个时候ts没有必要把他们全都声明为any类型,这样就失去了使用ts的意义。这个时候我们可以使用联合类型。
let date:string | number | boolean;
date = 1
date = '1'
date = true //都可以
date = [] //报错
//这种声明方式常用于函数的参数类型声明
这里要注意ts的自动数据类型推断
let date:string | number | boolean;
date = '1'; //我们把date赋值为string类型
date = 1; //我们把date赋值为number类型
date.length; //报错,因为ts推断此时date为number类型,而length是string类型的方法。
date = '1'; //我们把date赋值为string类型
date.length; //正确
8.never类型:用于标记永远不会存在的类型。多用于处理错误或者防止死循环。
因为实在不常用,这里就先不举例了。
9.null undefined
这两个类型是所有类型的子类型,早期版本和其他数据类型都不冲突,但新版本进行了严格化处理,不可以随便赋给其他类型变量了,否则报错。
10.interface 接口
我们可以直接定义一个接口,来形容我们声明的类或对象的形状。
//定义Person约束,字段的数量和类型都不可更改。
interface Person {
name:string;
age:number;
}
//声明tom时把Person约束赋给tom,无论多加字段、少写字段、类型修改都会报错。
let tom:Person = {
name:'Tom',
age:25
}
//也可以设置可选字段
interface Person {
name:string;
age?:number; //这样age字段在声明时可加可不加,都不会报错。
}
//声明tom时把Person约束赋给tom,无论多加字段、少写字段、类型修改都会报错。
let tom:Person = { //但是依然不允许自己添加属性。
name:'Tom'
}
有时候我们在声明对象的时候会有这种情况,我希望某个字段必填;某个字段选填,但一旦填写则必须是某种类型;其他的字段都可填可不填,且不限制类型。这时候我们就可以用到索引签名。
//索引签名
interface Person {
name:string
age?:number
[propName: string]:any
}
let tom:Person = {
name:'Tom',
from:'US'
}
有时候我们还希望规范某些字段为只读字段,不希望后续去做修改。
//readonly 只读属性
interface Person {
readonly name:string
}
let tom:Person = {
name:'Tom'
}
tom.name = 'Jerry' //Cannot assign to 'name' because it is a read-only property