TypeScript 的泛型化常用技巧

类型推导

目前 TS 的类型推导,仍不算完美。假定我们想做一个类似 useFetch / useLoader 这样的封装,思维的习惯会聚焦在 Query / Result 这两个类型上(就是 Input/Ouput),但围绕这两个类型做函数参数或 Object 类型,来实现的类型推导体系(即在实际调用层,通过实际的参数,来取代泛型的声明),目前在 TS 上是有一些问题的(不是做不到,是很绕也很繁琐)。

在 TS 里,更有效的做法,是关注载体(而不是关注端点)。比如:https://gitee.com/janpoem/use-the-loader/blob/master/src/useTheLoader.ts

即:type Loader<Q, R> = (Q) => Promise<R>。Loader 自身就负载了 Query / Result,然后通过 infer 即可提取出 Loader 的 Q/R。

这里又有另外一个问题,即 Parameters 这个在类型推导中使用的局限性。他无法有效的展开数组元素的类型推导。使用这个会让你需要写很多的 ts-ignore 和 eslint-disable-next-line。

回归 interface —— 泛型声明过多

假定我们做一个数据视图,这个视图包含两种以上截然不同数据结构。我们首先会习惯用泛型和类型推导做,这样能做到,但存在的问题是,关联的组件、函数、Class,都要一个一个套上对应的泛型声明,非常麻烦,维护难度高。

这时候,可以回归到 interface 的方式上,即:

intreface BasicSheetData {
	type: string;
	// 基础结构体
}

interface ASheetData extends BasicSheetData {
	type: 'a',
	// ASheet 结构体
}

interface BSheetData extends BasicSheetData {
	type: 'b',
	// BSheet 结构体
}

// 通过函数将类型推到成某个类型
const isASheetData = (d: BasicSheetData): d is ASheetData => d.type === 'a';
const isBSheetData = (d: BasicSheetData): d is BSheetData => d.type === 'b';

function usage(data: BasicSheetData): void {
	if (isASheetData(data)) {
		// 这 scope 里,data 被推导成 ASheetData
		// do something for ASheetData
	}  else if (isBSheetData(data)) {
		// 这 scope 里,data 被推导成 BSheetData
		// do something for BSheetData
	}
}

越到底层,越只需要关注 BasicSheetData。具体到具体类型,关注具体类型。公共组件,则通过 isXX 方法,来将 BasicSheetData 推导成特定类型即可。

这样就能大大简化了你的类型声明(尤其批评国外现在各种 npm 库,那个泛型满天飞,比如 react-hook-form,本质上用不到那些泛型)。

到底是 type 还是 interface,是 , 还是 ;

回到 TS,我才发现我对 C 语言是有多偏执,我是对 type (struct 声明方式)真的是情有独钟。

但在使用过程还是应该要注意,interface 能准确表达继承的涵义,尤以 TS 这种泛型的声明模式 (基于 extends ,不支持 Scala 那种),如果在类型设计存在继承关系的,还是应该要用 interface

type T = P & { } 并不算做准确的类型继承,这里 T 和 P 是两种类型,T 具有 P 部分属性,彼此无关联性(尤其是,interface 允许 override,type 的 & 会让一个属性具备两种类型检查,你必须明确声明 Omit<P, 'prop'> & {})。

但,interface 和 type 之间,可以互相串,比如:

type T = {}

interface A extends T {}

type B = A & {}

其次是,type 和 interface 里的字段声明,到底用 , 还是 ;,我是习惯用 ,,主要是这样的结构易于被复制、粘贴,或者是将某个 JS/JSON 结构,改写为类型声明,这样快。其实无区别,TS 最终都要转译,最终转译产物是 ;

两者之间也可以共用共存,没毛病,不必计较。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章