typescript怎么根据传入的参数判断函数的返回类型
需求
现在我们有一个方法
function func() {
//...
}
我们给他加一个参数
function func(param: any) {
//...
}
然后这个方法的返回值是这个参数的类型
function func(param: any): (typeof param) {
// ...
}
然后你会发现,这根本判断不出来,func
的返回值无论如何都是 any
,因为 typeof param
在编写的时候就已经被 typescript
判断了,这意味着 typeof param
实际上已经变成了常量 any
。不会因为传入的 param
而发生改变。
泛型
很明显,我们要用泛型。
function func<T>(param: any): T {
// ...
}
这个时候假如没有返回值会报错,假设我们的返回值是自己 param
;
function func<T>(param: T): T {
// ...
return param;
}
这时候你会发现
const a = func(1);
能够判断 a
的类型了。
但是这是最简单的情况,显然在大多数时候我们不能直接返回 param
,我们通常需要进行对 param
的类型判断,然后,再返回相应的值,并且确保返回值的类型是 T
。
限定范围
如果你想要限定 T
的范围,你可以使用 extends
;
function func<T extends string>(param: T): T
你可以规定 T
的范围到复杂类型;
function func<T extends string | number>(param: T): T
这个时候,在 func
中,你可以将 param
用 param as string
或 param as number
进行类型收窄。
返回参数的返回类型
有时候我们会遇到更复杂的情况,传入的 param
是一个可能返回任何值函数,这意味着它的类型对我们来说是 () => any
,而我们需要让 func
返回这个函数的返回值。
例如,有一个方法名叫 gene: () => number
,那么就要求 func(gene)
的类型是 number
;
首先,我们可以参考一下上面的方案
function func<T extends () => any>(param: T): T
然后就很简单了,由于类型收窄,我们知道 T
肯定是一个函数,这个时候我们可以用到 Typescript
提供给我们的一个工具 ReturnType
;
function func<T extends () => any>(param: T): ReturnType<T>
试一下
function func<T extends () => any>(param: T): ReturnType<T> {
// ...
return param();
}
const a = func(() => 1);
可以看到 a
的类型是 number
。
使用场景
生成一个任意随机长度的 generator
类型返回值的数组(这里我用到了mockjs)
function mockRandomList<G extends () => any>(
min: number,
max: number,
generator: G
): Array<ReturnType<G>> {
return new Array(Random.integer(min, max))
.fill(undefined)
.map(() => generator()) as Array<ReturnType<G>>;
}
这里 generator
就是生成器,生成一个对象,然后通过 map
的方式生成多个对象出来。
箭头函数
还可以把它改造成箭头函数
const mockRandomList1: <G extends () => any>(
min: number,
max: number,
generator: G
) => ReturnType<G>[] = (min, max, generator) => {
return new Array(Random.integer(min, max))
.fill(undefined)
.map(() => generator());
};
只不过这样在函数内部就不能使用 G
了。
转载自:https://juejin.cn/post/7005870555123417124