我希望getInjectData
函数根据我传入的injects
自动返回每个注入函数的返回值的合并类型。
代码是:
function getInjectData ({ injects }) {
cosnt data = {}
for (let inject of injects) Object.assign(data, inject())
return data
}
function injectUser () {
return { user: { name: 'Jack' } }
}
function injectBook () {
return { book: { author: 'Jack' } }
}
const injectData = getInjectData({ injects: [injectUser, injectBook] })
因此,我希望injectData
的类型为:
{
user: {
name: string
}
book: {
author: string
}
}
当然,我知道可以通过将泛型传递给getInjectData
来实现此要求:
interface InjectData {
user: {
name: string
}
book: {
author: string
}
}
const injectData = getInjectData<InjectData>({ injects: [injectUser, injectBook] })
但是应该有一种自动推测的方法吗?
答案 0 :(得分:1)
您确实必须帮助编译器解决这一问题。推断变量data
的类型为{}
,该变量太宽。并表示data
的预期类型涉及一些跳跃。
这就是我要做的。首先,我将使您的函数具有以下通用性:
function getInjectData<T extends () => object>({ injects }: { injects: T[] }) {}
通过这种方式,编译器期望injects
将是产生某些对象类型的无参数函数数组。然后,data
实际上应该是所有那些返回的对象类型中的intersection。
检查数组的元素时,自然会得到一个并集而不是一个交集。幸运的是,有[一种将联合变成交集的方法](https://stackoverflow.com/a/50375286/2887218 ):
type UnionToIntersection<U> = (U extends any
? (k: U) => void
: never) extends ((k: infer I) => void)
? I
: never;
此外,完成后,您可能会遇到像{a: string} & {b: number} & {c: boolean}
这样的丑陋交叉点,而不是像{a: string, b: number, c: boolean}
这样的单一类型。您可以使用其他类型的别名将它们转换为:
type Prettify<T> = [T] extends [infer U] ? { [K in keyof U]: U[K] } : never;
(这使用条件类型推断和映射类型来遍历属性并创建单个对象)。
这就是我声明data
的方式:
function getInjectData<T extends () => object>({ injects }: { injects: T[] }) {
const data = {} as Prettify<UnionToIntersection<ReturnType<T>>>;
for (let inject of injects) Object.assign(data, inject());
return data;
}
请明确说明:T
是返回对象的函数类型的并集。 ReturnType<T>
使用built in type alias产生这些返回类型的并集。 UnionToIntersection<ReturnType<T>>
是这些返回类型的交集,而Prettify<UnionToIntersection<ReturnType<T>>>
是表示该交集的单个对象类型。让我们尝试一下:
function injectUser() {
return { user: { name: "Jack" } };
}
function injectBook() {
return { book: { author: "Jack" } };
}
const injectData = getInjectData({ injects: [injectUser, injectBook] });
/*
const injectData: {
user: {
name: string;
};
book: {
author: string;
};
}
*/
对我很好。希望能有所帮助;祝你好运!