1. 为什么要使用TS和TS运行环境搭建
1.1 TypeScript是什么?
TypeScrip
是微软开发的一个开源编程语言,通过在JavaScript
的基础上添加静态类型定义构建而成,TypeScript
通过TypeScript
编译器或Babel
转译为JavaScript代码,可运行在任何浏览器,任何操作系统。
1.2 为什么使用TS?
- 友好的
IDE
提示 - 强制类型,防止报错
- 语言编写更加严谨
- 快速查找到拼写错误
JS
超集,扩展新功能
下面来几个例子体验一下
1.3 TS的使用和TS运行环境搭建
目前 TypeScript
的编译有两种方式。一种是使用 TypeScript
自家的编译器 typescript
编译,一种就是使用 Babel + @babel/preset-typescript
编译(这种后面再说)。
使用TS编译器编译ts文件
- 需要先安装
typescript
模块
npm install -g typescript
- 使用
tsc
命令编译
tsc index.ts
需要说明的是Ts默认的是全剧环境,只要文件使用模块化操作那么就会变成局部属性
如下图所示:
如果有一些编译上的特殊需求可以使用 tsconfig.json
,可以使用 tsc init
命令,也可以自己创建文件
可以看下图先简单了解一下
2. 声明空间
在 TypeScript
里存在两种声明空间:类型声明空间与变量声明空间。
2.1 类型声明空间
类型声明空间包含用来当做类型注解的内容。
class Foo{}
type Bus = {}
interface Bar{}
你可以将 Foo
,Bus
,Bar
作为类型注解使用,示例如下:
let foo:Foo
let bus:Bus
let bar:Bar
2.2 变量声明空间
变量声明空间包含可用作变量的内容。
class Foo {}
const someVar = Foo;
const someOtherVar = 123;
2.3 需要注意点:
- 两个声明空间是不能进行相互赋值操作的,如下图:
- 上文中的
class Foo
比较特殊,它既能为变量赋值,也能为类型注解。因为class
既提供了一个类型Foo
到类型声明空间,又同样提供了一个变量Foo
到变量声明空间。
3. 类型注解与类型推断
3.1 类型注解(type annotation)
就是在声明变量的时候,显式的声明他的类型
let message:string = 'hello'
上面的:string
就叫做一个类型注解,它的意思就是告诉程序,变量message是一个字符串类型
类型注解能够把我们上面说的两个空间联系到,如下:
// 1. 在类型声明空间声明了一个类型Message
type Message = string;
// 2. 在变量声明空间声明了一个变量message,并通过类型注解声明了变量message是一个Message(string)类型
let message: Message = "hello";
类型注解能够强制变量的类型,如果不进行类型注解,TypeScript
会帮助我们进行类型推断。
3.2 类型推断(type inferrence)
TypeScript
能根据一些简单的规则推断(检查)变量的类型。例如:
let foo = 123; // foo 是 'number'
let bar = 'hello'; // bar 是 'string'
foo = bar; // Error: 不能将 'string' 赋值给 `number`
4. 类型分类与联合类型与交叉类型
4.1 类型分类
Typescript
总共可以把基本类型、对象类型、TS新增类型三大部分
- 基本类型
string
、number
、boolean
、null
、undefind
、symbol
、bigint
- 对象类型
[]
、{}
、function(){}
- ts新增类型
any
、never
、void
、unkonwn
、enum
4.2 联合类型
类型之间进行或的操作
let a: number | string = 1
a = '1'
4.3 交叉类型
类型之间进行与的操作
type A = {
username: string
}
type B = {
age: number
}
let a: A & B = {
username: 'coder',
age: 24
}
5. never、any、unknown类型
5.1 never
表示永远不存在的值的类型 (用的很少)
// 因为a不可能即使number又是string,a是一个永远不存在的值,ts推断出是never
let a: number & string //never
下面是一个never的应用
function foo(number: 1 | 2 | 3) {
switch (number) {
case 1:
break;
case 2:
break;
default:
const n:never = number // 检测number是否可以走到这里,看所有值是否都被使用到
}
}
5.2 any
any
表示任意类型,ts
不会进行检测,写法可以理解为和js一样。
5.3 unkonwn
可以理解为不知道的类型,any
类型相对应的安全类型
6. 类型断言与非空断言
6.1 类型断言
类型断言主要用于当 ts
推断出的类型满足不了我们的需求,与手动指定一个类型。
let a: unknown = 123
(a as []).map(() => {})
6.2 非空断言
非空断言也是断言的一种,它会排除掉变量中的 null 和 undefeind。告诉ts我的值不是空的
let b: undefined | string = undefined
b!.length // b的类型为undefined 和 string ,非空断言排除了undefined所以能调length属性
断言能逃过 ts
的类型检测(就相当于告诉ts不用管了,我说是什么类型就是什么类型,我说非空就非空),但是上面的代码最终执行时还是会报错。所以用断言的时候要小心,这种做法危险出问题了后果自负。
7. 数组类型与元祖类型
7.1 数组类型
定义数组类型的两种写法
let number: number[] = [1,2,3]
let number: Array<number> = [1,2,3] // 泛型的写法
7.2 元组类型
元组类型允许表示已知元素数量和类型的数字,各元素的类型不必相同。可以看成是数组的特殊形式。
let a: [number|string] = [1,'2']
8. 对象类型与索引签名
8.1 对象类型
type A = {
username: string
age?: number // ? 表示可选
}
let a: A ={
username: 'coder'
}
8.2 索引签名
索引签名的思想是在只知道键和值类型的情况下对结构未知的对象进行类型划分。
索引签名的语法相当简单,看起来与属性的语法相似,但有一点不同。我们只需在方括号内写上键的类型,而不是属性名称:{ [key: KeyType]: ValueType }
。
type A = {
[index: string]: any
}
let a: {
username: 'coder'
}
[index: string]: any
是一个索引签名,它告诉TypeScript a 必须是一个以string 类型为键,以 any 类型为值的对象。
如果你不知道你要处理的对象结构,但你知道可能的键和值类型,那么索引签名就是你需要的。
9. 函数类型与void类型
9.1 函数类型
定义一个函数类型
function foo(n:number):number {
return n
}
foo(1)
ts要求函数的形参和实参必须相同,可以通过可选来控制参数不用一致
function foo(n:number, n1?:string):number {
return n
}
foo(1)
foo(1, 'hello')
出了上面的写法定义函数类,还可以用表达式
let foo: (n: number) => number = function(n) {return n}
9.2 void类型
表示函数没有任何返回值得到的类型
let foo = () => {} // foo的类型是 () => void
函数返回void和undefined的区别
- void: 可以不return 可以return空 也可以return undefined
- undefined: 不能不return
10. 函数重载与可调用注解
10.1 函数重载
函数重载是指函数约束传入不同的参数,返回不同类型的数据,而且可以清晰的知道传入不同的参数得到不同的结果
function add (num1:number| string, num2:number|string) {
return num1 + num2 // × 运算符“+”不能应用于类型“string | number”和“string | number”
}
- 如果希望可以对字符串和数字类型进行相加,可以用函数的重载
function add (num1:string, num2: string) : number
function add (num1:number, num2: number) : number
function add (num1:number, num2: string) : number
function add (num1:string, num2: number) : number
function add (num1:any, num2:any): any {
return num1 + num2
}
add(10, 20) // 执行了第2行函数定义
add(10, '20') // 执行了第3行函数定义
10.2 可调用注解
TS
支持我们使用类型别名或接口来定义一个可被调用的类型注解
type A = {
(): string
}
上面这个类型别名定义了一个可调用注解,它表示一个返回值为 string 的函数。
可调用注解可以针对函数重载进行类型注解
type A = {
(n1:number,n2: number):number,
(n1:string,n2:string): string
}
function add(n1: number, n2: number): number;
function add(n1: string, n2: string): string;
function add(n1: number | string, n2: number | string): number | string {
if (typeof n1 === "string" && typeof n2 === "string") {
return n1 + n2;
}
if (typeof n1 === "number" && typeof n2 === "number") {
return n1 + n2;
}
}
let a: A = add
11. 枚举类型
枚举类型是为数不多的TypeScript特性有的特性之一:
- 枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型;
- 枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型;
enum Direction {
LEFT,
RIGHT,
TOP,
BOTTOM
}
枚举类型默认是有值的
上面的枚举值可以看做
enum Direction {
LEFT = 0,
RIGHT = 1,
TOP = 2,
BOTTOM = 3
}
当然也可以手动赋其他值