备战面试!重拾TypeScript第二天

208 阅读7分钟

更文第二天,接着总结TypeScript知识点

枚举

定义 枚举(enum)的功能类似于字面量类型+联合类型组合的功能,来描述一个值,该值只能是 一组命名常量 中的一个

格式

1、使用 enum 关键字定义枚举

2、一般约定首字符大写

实例

enum Direction {
up,
Left,
Right,
down,
}
function changeDirection(a: Direction) {
console.log(Direction.up) //0
//'0': 'up',
//'1': 'Left',
//'2': 'Right',
//'3': 'down',
//up: 0,
//Left: 1,
//Right: 2,
//down: 3
}
changeDirection(0)

枚举-枚举的值

枚举类型和ts中其他的类型不一样,枚举类型不仅仅是类型,还是一个值。

解释

1、type定义的类型是没有值的

2、枚举定义的类型是有值的。

// 枚举和type对比
// type NewType = string | number | boolean
//console.log(NewType)// 输出类型是没有意义的
enum NewType {
up,
Left,
Right,
down,
}
console.log(NewType.Right, 555) //打印的值是2

默认情况下,枚举的值是数值。默认为:从 0 开始自增的数值

//up=等于10时,后面的值一次递增, Down -> 11Left -> 12Right -> 13
enum Direction { Up = 10, Down, Left, Right }
枚举的值可以自定义
enum Direction { Up = 2, Down = 3, Left = 8, Right = 16 }

字符串枚举 字符串枚举没有自增长行为,因此,字符串枚举的每个成员必须有初始值

enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}

应用场景

后端用 0, 1来标识性别,但是0,1在代码中不好读,此时可以用枚举来约定

//   枚举应用场景
enum Genter {
男,
女,
}
type user = {
name: string
genter: Genter
}
const xiaowang = {
name: '小王',
genter: Genter.男,//后端拿到的值就是0
}

any 类型

any: 任意的。当类型设置为 any 时,就取消了类型的限制。

let obj: any = { x: 0 }//此时obj可以被设置成任意类型
obj.bar = 100
obj()
const n: number = obj

使用any的场景

1、函数就是不挑类型。 例如,console.log() ; 定义一个函数,输入任意类型的数据,返回该数据类型

2、临时使用 any 来“避免”书写很长、很复杂的类型

原则:不推荐使用 any!这会让 TypeScript 变为 “AnyScript”(失去 TS 类型保护的优势)

类型断言

格式 关键字: as

const 变量 = 值(大的类型) as 类型(具体的类型)

关键字 as 后面的类型是一个更加具体的类型(HTMLAnchorElement 是 HTMLElement 的子类型)

场景

const img = document.getElementById('img') as HTMLImageElement
img.src

场景2 知道后端的结果会是一个类型,但这个结果是用ajax拿到的,不好直接给初始值,又希望得到输出提示的效果

//知道后端的结果会是一个类型,但这个结果是用ajax拿到的,不好直接给初始值,又希望得到输     出提示的效果
 type user1 = {
id: number
name: string
}
const u1 = {} as user1
console.log(u1.name) //这里就会有提示

typeof

TS 提供了 typeof 操作符:可以用来获取变量或属性的类型

格式 type 类型 = typeof 常量

实例

const res = { name: '小花', city: '武汉', skills: ['js', 'css'] }
// 定义一个类型来获取res的变量res的类型
type Stu = typeof res
const obj: Stu = {
name: '小王',
city: '北京',
skills: ['java', 'html'],
}

使用 typeof 操作符来获取变量 p 的类型,结果与第一种(对象字面量形式的类型)相同

注意:typeof 只能用来查询变量或属性的类型,无法查询其他形式的类型(比如,函数调用的类型)

keyof

获取某个对象类型的属性名来构成新类型

格式

type 类型 = keyof 类型
type 类型 = keyof 对象常量

示例

type obj2 = { name: '小花'; city: '武汉'; skills: ['js', 'css'] }
type Sku1 = keyof obj2
// Sku1='name'|'city'|'skills'
const c: Sku1 = 'name'

泛型(重点)本质上是参数化类型

泛型,顾名思义,就是可以适用于多个类型,使用类型变量(比如T)帮助我们捕获传入的类型,之后我们就可以继续使用这个类型。

本质是参数化类型,通俗的讲,就是所操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和函数的创建中,分别成为泛型类泛型接口泛型函数

泛型-泛型函数

泛型函数: 这个函数的参数类型或者返回值的类型可变的

格式

function 函数名<类型变量1,类型变量2,...>(参数1:类型1,参数2:类型2,...): 返回值类型 {
}

在函数名称的后面写 <>(尖括号),尖括号中添加类型变量

类型变量相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)

// 调用泛型函数时传过来参数,会通过类型推论<T>的类型就等于number
function getToken<T>(a: T): T {
return a
}
const num1 = getToken<number>(10) //太麻烦
const num = getToken(1) //可以利用ts的类型推断简化泛型函数的调用
console.log(num, num1, 44)

练习

// <T>接收的类型时调用useState时穿过来的类型,函数的参数类型和返回值都是<T>
function useState<T>(value: T): [T, (a: T) => T] {
const setValue = () => {
  return value
}
return [value, setValue]
}
//  接收返回值是一个元组
const str = useState('123') //传入的类型为string
const [num2, setNum] = useState(123) //传入的类型为number

泛型-泛型约束

默认情况下,泛型函数的类型变量 T 可以代表多个类型,这导致在泛型函数内部无法访问任何属性 默认情况下,泛型函数的类型变量 T 可以代表多个类型,这导致在泛型函数内部无法访问任何属性 比如,fn('a') 调用函数时获取参数的长度:

function fn<T>(value: T): T {
// 这里value. 不会有提示
console.log(value.length)// 这里会报错
return value
}
fn('a')

T可以代表任意类型,无法保证一定存在 length 属性,比如 number 类型就没有 length 此时,就需要为泛型添加约束来收缩类型(缩窄类型取值范围),从而得到类型提示

解决方法一、

// 指定更加具体的类型
//这里把从任意类型的数据  -----> 任意类型的数组。
function fn<T>(value: T[]): T[] {
// 这里value. 不会有提示
console.log(value.length) // 这里会报错
return value
}
fn([1, '1'])

解决方法二、

// 对已有类型做继承,要求传入T类型必须要有length属性。
interface ILength {
length: number
}
// 这里T继承了ILength的类型,要求传入的T类型的length属性必须时number才行
function fn1<T extends ILength>(value: T): T {
// 这里value. 不会有提示
console.log(value.length) // 这里会报错
return value
}
fn1('1')
fn1([])

场景

// 对getProp函数进行改造
//T extends object 表示: T 应该是一个对象类型,如果不是 对象 类型,就会报错
function getProp<T extends object, Key extends keyof T>(obj: T, key: Key) {
return obj[key]
}
let person = { name: 'jack', age: 18 }
getProp(person, 'name')
let person1 = { name: 'jack', age: 18, genter: '男' }
getProp(person1, 'genter')

泛型接口

在接口中使用泛型来使用,以增加其灵活性,增强其复用性

格式

interface 接口名<类型变量1,类型变量2...> {
属性名1:类型1,
属性名2:类型2,
属性名3:类型3
}

示例

interface MyArray<T> {
length: number
push(n: T): void //参数是传过来的类型T
pop(): T //返回值是传过来的类型T
reverse(): T[] //返回值是传过来的类型T的数组
}
let arr: MyArray<number>
//   arr.push()

注意

1、在接口名称的后面添加 <类型变量>,那么,这个接口就变成了泛型接口

2、接口的类型变量,对接口中所有其他成员可见,也就是接口中所有成员都可以使用类型变量

3、使用泛型接口时,需要显式指定具体的类型

实际上,JS 中的数组在 TS 中就是一个泛型接口。

// 我们在使用数组时,TS 会根据数组的不同类型,来自动将类型变量设置为相应的类型
const strs = ['a', 'b', 'c']
// 鼠标放在 forEach 上查看类型
strs.forEach
const nums = [1, 3, 5]
// 鼠标放在 forEach 上查看类型
nums.forEach

泛型工具类型

Partial

Partial用来基于某个Type来创建一个新类型,新类型中所有的属性是可选的

格式

type OldType = { 属性1:类型1,....}
type NewType = Partial<OldType>

示例

type Props =  {
id: string
children: number[]
}
type NewType1 = Partial<Props> 
// 构造出来的新类型 NewType1 结构和 Props 相同,但所有属性都变为可选的。
type NewType1 =  {
 id?: string
 children?: number[]

}

Readonly

Readonly<Type> 用来构造一个类型,将 Type 的所有属性都设置为 readonly(只读)--不可修改。

type Props1 = { id: string; children: number[] }
// 得到新类型,其所有的属性都是只读的
type ReadonlyProps = Readonly<Props1>
// 构造出来的新类型 ReadonlyProps 结构和 Props 相同,但所有属性都变为只读的。
let props: ReadonlyProps = { id: '1', children: [] }
props.id = 2 //报错

Pick

从已有的类型中挑选一组属性,来构造新类型

格式: Pick<老类型, 挑选的属性>

type Props2 = { id: string; title: string; children: number[] }
type PickProps = Pick<Props2, 'id' | 'title'>
第二个类型变量传入的属性只能是第一个类型变量中存在的属性。

TypeScript的基础就差不多回顾完了,我还会接着更新的,大家一起加油