如何从类型联合创建仅包含公共属性的类型?

时间:2019-05-29 18:43:02

标签: typescript

我想映射数组的并集,如何使其安全键入?

我有一个解决方案,但我想避免对类型联合中的类型进行硬编码。 在按预期方式计算newArr1时,出现错误:Property 'field2' does not exist on type 'Common<A, B>' 计算newArr2时是否有办法得到相同的错误?

link to code

interface A {
    field1: string
    field2: number
}
interface B {
    field1: string
}

type Common<A, B> = {
    [P in keyof A & keyof B]: A[P] | B[P];
}

function mapArray(arr: A[] | B[]) {

    const newArr1 = (arr as Common<A, B>[]).map(i => i.field2) // error

    // how can I get the same error without hard-coding the types from the type union?
    const newArr2 = (arr as MagicEventuallyFromJcalz<typeof arr>).map(i => i.field2)

    return newArr1
}

1 个答案:

答案 0 :(得分:0)

感谢jcalz和William Lohan!

一个实际用例:对于来自外部api的2个不同的请求,我得到2个不同的响应:

  1. 由用户组成的数组,其中包含有关每个用户的许多详细信息,并且
  2. 一个数组,其中用户具有上一点的细节子集

使用相同的函数从上方解析两个数组中的一个,我想以类型安全的方式获取用户的ID(id是两个数组中用户的公共属性),1)和2)无需在函数体中对数组类型进行硬编码。根据jcalz的评论,我能够做到这一点。您应得到解决方案的功劳,如果您发布答案,我会将其标记为已接受。

我找到的解决方案(link to code):

interface DetailedUser {
    id: number
    many: number
    other: string
    fields: boolean
}
interface CompactUser {
    id: number
}

type Common<T> = Pick<T, keyof T>

type UnpackedFromArray<T> = T extends (infer U)[] ? U : never

function getUserIdsFromApi(usersJsonFromApi: DetailedUser[] | CompactUser[]) {

    // works as expected: in both lines below, a ts error is raised
    // note that the types (DetailedUser[], CompactUser[]) are not hard-coded, but determined from variable usersJsonFromApi

    const userIds1 = (usersJsonFromApi as Common<UnpackedFromArray<typeof usersJsonFromApi>>[]).map(i => i.other)

    const userIds2 = (usersJsonFromApi as Common<typeof usersJsonFromApi[number]>[]).map(i => i.other)

    return userIds1
}