在TypeScript中拾取并展平类型签名

时间:2018-07-20 05:44:53

标签: typescript

我正在查看标准库中包含的一些较酷的类型函数,因此开始玩游戏。这样在TypeScript中实际上有可能吗?

interface OriginalType {
    A: { a : string }
    B: { b1 : string, b2: number }
    C: {}
    D: {c: string}
}


const r : {a: string, b1: string, b2: string} = pickAndFlatten<OriginalType>(['A', 'B'])

1 个答案:

答案 0 :(得分:5)

我们可以通过创建所选属性类型的交集来做到这一点。

type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
type PickAndFlatten<T, K extends keyof T> = UnionToIntersection<T[K]>

UnionToIntersection由@jcalz here提供,您应该在那里看到说明(不要忘了感谢他:)。 T[K]将为我们提供密钥K的类型。如果K是键的联合,则T[K]将是联合中所有属性类型的联合。

要在函数中使用此参数,我们将需要两个类型参数,一个代表我们选择的类型,一个代表我们选择的键。

interface OriginalType {
    A: { a : string }
    B: { b1 : string, b2: number }
    C: {}
    D: {c: string}
}

type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
type PickAndFlatten<T, K extends keyof T> = UnionToIntersection<T[K]>

function pickAndFlatten<T, K extends keyof T>(o: T, keys : K[]) :PickAndFlatten<T, K>  {

    // Untested implemenattion 
    let entries = Object.entries(o)
        .filter(([k,v]) => keys.includes(k as K))
        .map(([k,v]) => v);

    return Object.assign({}, entries) as any;
}

let o : OriginalType;
const r  = pickAndFlatten(o, ['A', 'B']) // {a: string;} & {b1: string;b2: number;}