欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TypeScript 中几个小技巧

程序员文章站 2024-02-19 18:11:28
...

泛型的用法

本来以为在开发中基本用不到泛型,没想到今天还是碰到了。公司的项目是用 React 写的,其中需要使用 useSelector 的 hook 从 redux 获取数据,代码如下:

const { auditFilterOptions, auditRecords, auditTableLoading } = useSelector(state => {
	auditFilterOptions: state.getIn(["resource", "auditFilterOptions"]),
	auditRecords: state.getIn(["resource", "auditRecords"]),
	auditTableLoading: state.getIn(["auditTableLoading ", "auditTableLoading "])
})

在使用 TypeScript 的时候,提示需要给形参 state 声明类型。但是我们知道,state 是一个对象,上面挂载了 getIn 方法。因此,在声明类型的时候,势必要声明 getIn 方法的入参和返回值类型。但是在上面代码中,每一个 store 的字段,对应的数据类型是不一样的,这导致每次调用 getIn 方法的返回值可类型可能是不一样的:

type AuditFilterOptions = {
	limitMinTime: string;
	operateUsers: string[];
	serviceTypes: string[];
	tenants: string[];
}

type AuditRecords = {
	total: number;
	page: number;
	rows: {
		operateTime: string;
		operateMessage: string;
		operateUser: string;
		operateType: string;
	}[];
}

type AuditTableLoading = boolean;

之前同事在开发的时候,直接简单粗暴:

interface State {
	getIn: Function;
}

这样操作,虽然类型检查不会报错,但是无疑丢失了类型信息,返回类型直接被推导为 any ,无法获取到对象属性的类型了。那么需要怎么样才可以保留类型信息呢?

之前在 Java 里面用过函数重载,就是一个函数名可以有不同的类型定义,编译器通过不同的入参及入参类型调用对应的函数。在 TS 中也提供了函数重载机制:

interface State {
	getIn(a: string[]): AuditFilterOptions;
	getIn(a: string[]): AuditRecords;
	getIn(a: string[]): AuditTableLoading;
}

但是实际测试发现,由于入参都一样,编译器没办法区分类型,始终匹配到的是第一个返回值类型。

那么怎么样才能实现匹配不同类型的返回值呢?想到了泛型。泛型就是参数化类型,可以传入类型参数。按照这个思路,state 的类型可以这样声明:

interface State {
	getIn<T>(a: string[]): T;
}

对应 useSelector 就可以这样使用:

const { auditFilterOptions, auditRecords, auditTableLoading } = useSelector((state: State) => {
	auditFilterOptions: state.getIn<AuditFilterOptions>(["resource", "auditFilterOptions"]),
	auditRecords: state.getIn<AuditRecords>(["resource", "auditRecords"]),
	auditTableLoading: state.getIn<AuditTableLoading>(["auditTableLoading ", "auditTableLoading "])
})

然后也尝试过这个方案:

interface State<T> {
	getIn(a: string[]): T;
}

但这样的话,useSelector 就得拆开写了,太麻烦,还是上面的写法简单:

const { auditFilterOptions } = useSelector((state: State<AuditFilterOptions>) => {
	auditFilterOptions: state.getIn(["resource", "auditFilterOptions"])
})
const { auditRecords } = useSelector((state: State<AuditRecords>) => {
	auditRecords: state.getIn(["resource", "auditRecords"]),
})
const { auditTableLoading } = useSelector((state: State<AuditTableLoading>) => {
	auditTableLoading: state.getIn(["auditTableLoading ", "auditTableLoading "])
})

类型断言

在定义类型的时候,会遇到属性可能不存在的情况:

type Services = {
	metrics?: {
		cpuUsage: number;
		memoryUsage: number;
	}
}

那么在访问可能不存在的属性的时候,编译器会报错,提示该属性可能为 undefined :

const memoryUsage = Math.floor(pod.metrics?.memoryUsage /1024 / 1024);

这种情况怎么处理?很简单,使用类型断言就不会报错了:

const memoryUsage = Math.floor((pod.metrics?.memoryUsage as number) /1024 / 1024);