首页 > 解决方案 > 如果数组的每个元素都是一个函数,如何合并数组中的元素?

问题描述

export type MakeActionType = (name: string) => {[key: string]: string}
const combineActionType = <AT extends (MakeActionType | undefined)[]>(...actionTypeList: AT) => (name: string) => {
    return actionTypeList.reduce(
        (previous, makeActionType) => {
            const actionType = makeActionType ? makeActionType(name) : {}
            return {
                ...previous,
                ...actionType,
            }
        },
        {}
    )
}

现在我像这样应用上面的函数:

const abAction = combineActionType((name) => ({a: 'a'}), (name) => ({b: 'b'}))
const ab = abAction('ab')

我想ab包含ab属性,但ab返回{}类型,这就是为什么ab.aab.b不工作。

ab.a //err
ab.b //err

如何定义包含“a”和“b”属性的 ab 类型?

标签: typescript

解决方案


您需要明确告诉 typescript 的返回类型是什么reduce,typescript 将无法推断类型。

返回类型应该是所有函数返回类型的交集。我们可以使用类型查询 () 获取函数类型的联合,并且可以使用条件类型AT[number]获取返回类型。ReturnType要将返回类型的并集转换为交集,我们可以使用此处UnionToIntersection的类型(不要忘记支持 jcalz)

type UnionToIntersection<U> = 
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
export type MakeActionType = (name: string) => { [key: string]: string }
const combineActionType = <AT extends (MakeActionType | undefined)[]>(...actionTypeList: AT) => (name: string)  => {
    return actionTypeList.reduce(
        (previous, makeActionType) => {
            const actionType = makeActionType ? makeActionType(name) : {}
            return {
                ...previous,
                ...actionType,
            }
        },
        {} 
    )  as UnionToIntersection<ReturnType<Exclude<AT[number], undefined>>>
}


const abAction = combineActionType((name) => ({a: 'a'}), (name) => ({b: 'b'}))
const ab = abAction ('a') // { a: string } & { b: string }

游乐场链接


推荐阅读