对TypeScript的理解和为什么一定要TypeScript:
由于JS是一门 动态类型检(运行的时候去检查)而且变量的操作性很灵活、很容易写出 null is not an object、undefined is not a function 这些不可预知类型不匹配的隐患、在加上js是单线程、如果某个方法里面出现了这种报错就导致剩下的内容都无法执行、导致bug率太高、所以就衍生出TS、把动态类型语言变成了静态类型语言,在编译期间做类型的检查有什么好处呢?可以提前发现一些类型安全问题、除此之外还有编辑器的提醒和对代码的阅读性与如参的描述、重构等等都有好处!所以TypeScript被很多大型项目使用~
在线测试编辑器
在学习之前我们需要了解我们的案例需要在那里运行测试、这样有利于我们理解 地址
TS类型
- TS系统中有:number、boolean、string、object、bigint、symbol、undefined、null
- 包装类型:**
- 复合类型:Class、Array
- TS新增:Tuple、interface、Enum
- 四种特殊的类型: void 、nerver、any unknown
- TS的关键词: type、interface、typeof、in
元组(Tuple)元素个数和类型固定的数组
type Tuple = [number, string, boolean];
let ArrTuple:Tuple = [1,'2',true]
接口(interface) 描述函数、构造器、索引类型(对象、class、数组)等复合类型
```typescript interface IUser { name: string, age: number, getName(name?: string): string, maps: Map}
// class class Uer implements IUser { name: string age: number maps = new Map([ [‘name’, 1] ]); constructor(name: string, age: number) { this.name = name; this.age = age; } getName() { return this.name }
}
// 对象 & 对象内部方法 const obj: IUser = { name: “张三”, age: 19, getName(name: string) { return name }, maps: new Map([ [‘name’, 1] ]) }
//构造器 interface PersonConstructor { new(name: string, age: number): IUser; } function createPerson(ctor: PersonConstructor): IUser { return new ctor(‘zhangsan’, 18); }
// 动态添加对象属性 interface IPerson { [key: string]: string | number; } const obj1: IPerson = {}; obj1.name = ‘zhangsan’; obj1.age = 18;
<a name="iPLp6"></a>
#### 枚举(Enum) 一系列值的复合
```typescript
enum sex {
male = "男",
female = "女",
unknown = "未知",
}
let sexValue = sex.male;
// 2
enum color {
red = 10,
green,
yellow,
}
console.log(color.green) //11
console.log(color.yellow) //12
viod & never & any & unknown (特殊类型)
let any_: any // 是任意类型,任何类型都可以赋值给它,它也可以赋值给任何类型
let never_:never //代表不可达,比如函数抛异常的时候,返回值就是 never。
let unknown_:unknown // 是未知类型,任何类型都可以赋值给它,但是它不可以赋值给别的类型
let viod_:viod // 代表空,可以是 null 或者 undefined,一般是用于函数返回值
TS类型装饰
readonly(只读)
interface IPerson {
readonly name: string;
}
?(可选)
interface IPerson {
age?: number;
}
type tuple = [string, number?];
TS运算符
条件:extends ? :
// 传入一个类型、判断类型是否等于1、等于1返回true
type IsMan<T> = T extends 1 ? true : false;
type res = IsMan<1> // true
推导:infer (声明局部变量的关键字、和裁剪某些内容的声明字)
// 提取数组的第一个元素
type First<Arr extends unknown[]> = Arr extends [infer F, ...infer Rest] ? F : never;
type ArrFirst = First<[1,2,3]> // 1
// <Arr extends unknown[]> 这里是约束传入的Arr是一个数组
联合:| (类似js的 | 、代表类型可能是xxx)
type moreType = string | number | boolean
交叉:& (类似js的 &、代表多个类型进行合并)
type ObjType = { name:string }
type ObjType1 = { age:number}
let obj:ObjType & ObjType1 = {
name:'李四',
age:18
}
映射类型 (对象、class在TS中属于索引类型
let a =1
interface o{
name:string
age:number
}
typeof a; // number 与Object.keys略有相似
typeof o; // { name: string; age: number; }
/*
解释下方代码意思:MapType接收一个 key value对象、如果in 去遍历传入的T对象、得到每个Key
并通过keyof获取key的类型、和用T[key]获取对象的value
*/
type MapType<T extends Record<string,any>> = {
[Key in keyof T]: T[Key]
}
// 我们用案例去理解
// 案例1 把传入的对象value改成数组
type MapType<T> = {
[Key in keyof T]: [T[Key], T[Key], T[Key]]
}
type res = MapType<{a: 1}>; // {a: [1, 1, 1]}
- keyof T 是查询索引类型中所有的索引,叫做索引查询
- T[Key] 是取索引类型某个索引的值,叫做索引访问
- in 是用于遍历联合类型的运算符
重映射(as 运算符)
type MapType<T> = {
[
Key in keyof T
as `${Key & string}${Key & string}${Key & string}`
]: [T[Key], T[Key], T[Key]]
}
type res = MapType<{name:"z"}>; // {"name-name-name": ["z", "z", "z"]}
/*
这里的 & string (限制类型为string)
因为索引类型(对象、class 等)可以用 string、number 和 symbol 作为 key,
这里 keyof T 取出的索引就是 string | number | symbol 的联合类型,
和 string 取交叉部分就只剩下 string 了。
就像前面所说,交叉类型会把同一类型做合并,不同类型舍弃
*/
总结
TS基础部分已经完成、剩下的就是类型的转换计算部分!