简介

TypeScript一门是静态弱类型语言,准确的来说,TypeScript 是JavaScript的一个超集,可以把TypeScript文件编译成JavaScript文件,适用于任何JavaScript项目。

在JavaScript中有以下几个特点:

  • 没有类型约束,一个变量可能初始化的时候是字符串,一会又变成数字
  • 由于隐式类型转换的存在,有的变量的类型很难在运行前就确定。
  • 基于原型的面向对象编程,使得原型上的属性或方法可以在运行时被修改。
  • 是 JavaScript 中的函数,可以赋值给变量,也可以当作参数或返回值

这些特点是一把双刃剑,使得语言本身灵活发展无所不能,又使得它代码质量参差不齐,维护成本高,运行时错误多。而TypeScript的出现,很大程度上弥补了JavaScript的缺点。

我们熟知的JavaScript是动态弱类型语言,而TypeScript是静态弱类型语言。那么这两种类型又有什么区别呢?

动态类型:

动态类型是指在程序在运行之后才会进行类型检查,而这种方式往往会导致运行错误。

1
2
3
4
let foo = 1;
foo.split(' ');
// Uncaught TypeError: foo.split is not a function
// 运行时会报错(foo.split 不是一个函数),造成线上 bug

静态类型:

静态类型是指编译阶段就能确定每个变量的类型,这种语言的类型错误往往会导致语法错误。能够在代码编写阶段就能够发现错误

1
2
3
4
let foo = 1;
foo.split(' ');
// Property 'split' does not exist on type 'number'.
// 编译时会报错(数字没有 split 方法),无法通过编译

强类型:

对变量的类型有严格的限制,不允许改变变量类型,除非进行强制类型转换。

弱类型:

没有过多的约束,变量可以被赋予不同的数据类型。

数据类型

ts在js的数据类型基础上,新增了几种数据类型,分别是 void、any、never、元组、枚举和高级类型

基础类型

1
2
let str : string | boolean = 'hello world // 声明str变量 为string类型或者boolean类型
str = 10 //此时编辑器会提示错误 不能将类型“10”分配给类型“string | boolean”

数组

1
2
3
let arr1 : number[] = [1,2,3]
let arr2 : Array<number> = [1,2,3] //数组的声明有两种,其中Array是ts内置的一个泛型接口
let arr3 : Array<number | string> = [1,2,3,'4'] // 使用 | 表达符插入多种类型

元组

元组是一种特殊的数组 它限定了数组的类型于个数

1
2
3
4
let tuple : [string, number] = ['0', 1] //它规定了 第一个元素只能是string类型,第二个类型只能是number类型

tuple.push(2) //元组允许往其中插入新元素
console.log(tuple[2]) //但是添加的元素是不能访问的

函数

1
2
3
4
5
let add = (x : number, y : number) => x + y //函数的参数需要声明类型
let add = (x : number, y : number) : number => x + y //也可以为函数返回值声明,通常是可以省略的

let compute : (x : number, y : number) => number //当函数定义的时候声明了类型
compute = (a, b) => a + b //实现的时候就不用声明了

对象

1
2
let obj : {x: number, y: number} = {x:1, y:2} //对象声明时必须 定义它的属性的数据类型
obj.x = 3

symbol

1
2
3
let s1 : symbol = Symbol() // 可以显式的声明symbol类型
let s2 = Symbol() // 也可以直接创建一个 symbol
console.log(s1 === s2) //false

undefined, null

1
2
3
4
5
6
let un: undefined = undefined
let nu: null = null //当声明undefined和null以后,它就只能被赋值于它本身,

let num :number = 1
num = null
// 要想将其他类型的变量赋值为undefined和null,需要到 tsconfig.json中 将strictNullChecks配置项 设置为false

void

1
let noReturn = ()=>{} //表示没有任何返回值的类型

any

1
let s //当没有声明变量类型时默认就是any ,any可以代表任何类型 可以任意的赋值,any能完美兼容js

never

1
2
3
let error = ()=>{
throw new Error('err')
} // never表示永远不会有返回值

枚举类型

数字枚举

1
2
3
4
5
6
7
8
enum Role {
Zero,
One,
Two = 4,
Three
}
console.log(Role.Zero) //0
console.log(Role.Three) //5 数字枚举默认的是依次递增,可以以自己定义值

字符串枚举

1
2
3
4
enum Message {
Susscess = '成功了'
Fail = '失败了'
}

异构枚举

1
2
3
4
enum Role {
Zero,
Susscess = '成功了'
} // 将数字枚举 和字符串枚举混合

枚举成员

1
2
3
4
5
6
7
8
9
enum E {
// 枚举的成员有四种情况
a, //没有初始值
b = E.a, // 对已有枚举成员的引用
c = 1 + 1, // 常量表达式
// computed 需要被计算的枚举成员,他们的值不会在程序的编译阶段进行计算,而会保留到程序的执行阶段
d = Math.random(),
e = 'abc'.length
}

常量枚举

1
2
3
4
5
const enum Mouth {
Jan,
Feb,
Mar
} //使用const 定义的常量枚举,会在编译之后被移除。当只需要常量不需要枚举变量时,可以使用

接口

对象类型接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
interface List {
readonly id: number,// 只读属性 不允许修改
name: string,
age ? : number,//可选属性 可有可无

// 其二就是定义一个字符串索引签名, 表示用任意的字符串索引List,可以得到任意的结果
[x:string] : any

}//对象类型接口有点类似java中的实体类,可以事先定义若干字段
interface Result {
data: List[] //然后就将他用数组包起
}

function render(res: Result) {
res.data.forEach(val => {
console.log(val.id, val.name);
})// 定义一个函数,循环遍历其中的值 并打印
}

let result = {
data: [
{ id: 1, name: 'fish', sex:'男' },
{id:2, name:'张三'}
]
}

// 当传入的不是一个变量,而是一个字面量时,ts会进行类型检查,若想绕过类型检查可以使用类型断言的方式
// 就是告诉强制编辑器,它的类型
// 其一 可以在字面量前加上类型注解或者在末尾加上 as Result(推荐第二种)
render(<Result>{
data: [
{ id: 1, name: 'fish', sex:'男' },
{id:2, name:'张三'}
]
}
// as Result
)

函数类型接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 函数类型的定义方式
//1. 使用一个变量定义函数类型
let add : (x: number, y: number) => number

//2. 使用接口定义
interface Add {
// 参数类型 返回值
(x: number, y: number) : number
}

//3. 使用类型别名
type Add = (x: number, y: number) => number
let add : Add = (a, b) => a + b


混合类型接口

在混合类型接口中,既可以定义函数,又可以像对象一样 拥有属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface Lib {
(): void;
version: string;
doSomething(): void;
}

//let lib: Lib = (() =>{}) as Lib;
//lib.version = '1.0'
//lib.doSomething = () => {}

// 如果想创建多个lib,则需要使用函数封装一下
function getLib() {
let lib: Lib = (() =>{}) as Lib;
lib.version = '1.0'
lib.doSomething = () => {}
return lib;
}
let lib1 = getLib();
lib1.doSomething();
let lib2 = getLib();
lib2();