TypeScript
大约 7 分钟
JS是自由的流浪剑客,TS则是剑客做了带刀侍卫,有规矩将剑客约束了起来
优点:代码即文档、编辑器自动提示、一定程度上能够避免低级 bug、代码的可维护性更强等
可以说是JS的超集,遵循最新规范,扩展了JS的语法
类型(通俗定义)
- 强类型:不许改变变量的数据类型(给变量定义了一个类型,那么这个变量类型就不可改变),除非进行强制类型转换 如 Java、C#、Python、C/C++
- 弱类型:可以改变变量的数据类型 如 JavaScript, PHP
- 静态类型:在编译阶段确定所有变量的类型 如 Java, C#, C/C++
- 动态类型:在执行阶段确定所有变量的类型 如 JavaScript, PHP, Python
动态弱类型语言让人模糊的场景:
- 调用未注释说明的函数时,不知道传参的类型,只能去函数体中看
- 函数中对传入的参数进行各种判断假设
- 更改了一个数据的参数类型,但不知道还有多少地方调用
- 前后端联调时出现不一致的情况
- ...
- 导致造成类型思维缺失,开发不规范
因此:Facebook的Flow -- > 微软的TypeScript
TS 好处
- 编译时类型检查
- 语言扩展:如异步类型、装饰器、接口、抽象类
- 工具属性,可以编译成标准的JS
- ...
- 让开发者思考
安装与编译
npm install typescript -g # 安装
tsc helloworld.ts # 编译
tsc --init # 生成一个tsconfig.json 配置文件
# vscode中 菜单 任务-运行任务 tsc:监视-tsconfig.json 可以自动生成代码
# Hbuilder中 工具中安装typescript插件
TypeScript中的数据类型
- Boolean
- Number
- String
- Array
- Function
- Object
- Symbol
- undefined
- null
- void
- any
- never
- 元组 tuple
- 枚举 enum
- 高级类型
类型注解
作用:相当于强类型语言中的类型声明
语法: [变量/函数]:type
基础数据类型
let isOver: boolean = false; // 布尔类型
let num: number = 6; // 数字类型
let hexNum: number = 0xf00d;
let binNum: number = 0b1010;
let name: string = 'Hello World'; // 字符串类型
/* es6中的小撇号(模板字符串)*/
let name: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ name }.
I'll be ${ age + 1 } years old next month.`
/* 数组类型 */
let arr: number[] = [1,2,3]; // 类型元素数组
let arr1: Array<number> = [1,2,3]; // 泛型接口
let arr2: Array<number | string> = [1, 3, '2']; // 联合类型
let arr3: any[] = [1,2,3]; // 类型元素数组
/* 元组类型Tuple */
let x: [string, number];
x = ['hello', 10];
// x.push(2) 但是 x[2]会报错,所以不要这样使用
x = [10.'hello']; // error
// 当访问一个越界的元素,会使用联合类型替代:
x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型
console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString
x[6] = true; // Error, 布尔不是(string | number)类型
/* 枚举类型 enum
程序广泛地用于处理非数值的数据
在其它程序设计语言中,一般用一个数值代表某一状态,这种处理方法不直观,易读性差,
能在程序中用自然语言中有相应含义的单词来代表某一状态,考虑到某一变量可能取得值,
尽量用自然语言中含义清楚的单次来表示它的每一个值
实现原理:反向映射,字符串枚举是不可以用于反向映射的
不建议使用异构枚举
*/
enum Color {Red,Green,Blue} // || enum Color {Red = 1,Green = 9,Blue}
let c: Color = Color.Red; // 打印出下标 0
let colorName: string = Color[2]; // 'Green'
/* Any 任意类型
* 在对现有代码进行改写的时候,any类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。
* 你可能认为 Object有相似的作用,就像它在其它语言中那样。
* 但是 Object类型的变量只是允许你给它赋任意值 -
* 但是却不能够在它上面调用任意的方法,即便它真的有这些方法
**/
let notSure: any = 5;
notSure = false;
notSure = 'maybe';
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)
let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
let list: any[] = [1, true, "free"];
/* void 类型 */
// 表示方法没有返回值
function run():void {
console.log('run')
}
/* Null & Undefined*/
var num:number | undefined;
num = 123
console.log(num);
/* Never 类型 */
// 从来都不会出现的值
var a:never;
a=(()=>{
throw new Error('错误')
})()
/* Object */
/* 类型断言(类型转换) */
变量声明
- 尽可能地使用let来代替var
接口
起到一种规范和限制(约束)的作用: 属性类接口(对象类型接口),函数类型接口,可索引接口
对象类型接口
interface List {
readonly id: number;
name: string;
// [x:string]: any
// sex?: string
}
interface Result {
data: List[]
}
function render(result: Result) {
result.data.forEach(v => {
console.log(v.id, v.name)
})
}
let result = {
data: [
{ id: 1, name: 'A', sex: 'male' },
{ id: 2, name: 'B'}
]
}
render(result) // 假如直接用上述对象字面量就会报错, 可以加 as Result
可索引类型接口
函数类型接口
混合类型接口
类类型接口
接口继承接口
接口继承类
泛型
不预先确定的数据类型,具体的类型在使用的时候确定
泛型变量<T>
函数
var run = function():number {
return 123;
}
function getInfo(name:string,age:number):string {
return name + age;
}
// 方法的可选参数
// es5中方法的实参和形参可以不一样,但是ts中必须一样,如果不一样就需要配置可选参数
// 可选参数必须配置到参数的最后面!!!
function getInfo(name:string,age?:number):string {
if(age) {
return name + age;
} else {
return name;
}
}
alert(getInfo('lipeng'))
// 方法的默认参数
// es5中没法设置默认参数,es6和ts中可以设置默认参数
function getInfo(name:string, age:number = 20):string {
if(age) {
return name + age;
} else {
return name;
}
}
alert(getInfo('lipeng'))
// 方法的剩余参数 (三点运算符)
function sum(a:number, b:number, c:number, d:number):number {
return a+b+c+d;
}
function sum1(...result:[]):number {
var sum = 0
result.forEach(function(num){
sum += num
})
return sum;
}
sum1(1,2,44,5,7,8);
// 方法的重载
// java中方法的重载:指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况
// ts中的重载,通过为同一个函数提供多个函数类型定义来试下多种功能的目的
function getInfo(name:string):string;
function getInfo(age:number):number;
function getInfo(str:any):any {
if(typeof str === 'string') {
return str
} else {
return str + 10
}
}
// 箭头函数
// 箭头函数中的this指向上下文
setTimeout(() => {
alert('num')
},1000)
使用enum 维护常量
// 使用 const enum 维护常量
const enum TODO_STATUS {
TODO = 'TODO',
DONE = 'DONE',
DOING = 'DOING'
}
function todos(status:TODO_STATUS):number[] {
return []
};
todos(TODO_STATUS.TODO)
使用 VS Code 有时会出现,使用 tsc 编译时产生的问题与 vs code 提示的问题不一致 找到项目右下角的 Typescript 字样,右侧显示它的版本号,可以点击选择 Use Workspace Version,它表示与项目依赖的 typescript 版本一致。 或者编辑 .vs-code/settings.json
{
"typescript.tsdk": "node_modules/typescript/lib"
}
类
代码检查
两个方案:1、TSLint 2、ESLint + typescript-eslint-parser
TSLint 的优点:
- 专为 TypeScript 服务
- 不受限于 ESLint 使用的语法树 ESTree
- 能直接通过 tsconfig.json 中的配置编译整个项目,使得在一个文件中的类型定义能够联动到其他文件中的代码检查
ESLint 的优点:
- 基础规则比 TSLint 多很多
- 社区繁荣,插件众多
1. 使用TSLint
npm install --save-dev tslint
// 创建配置文件 tslint.jsonp
{
"rules": {
// 必须使用 === 或 !==,禁止使用 == 或 !=,与 null 比较时除外
"triple-equals": [
true,
"allow-null-check"
]
},
"linterOptions": {
"exclude": [
"**/node_modules/**"
]
}
}
// package.json中添加tslint脚本
{
"scripts": {
"tslint": "tslint --project . src/**/*.ts src/**/*.tsx",
}
}
// 运行检查
npm run tslint