简体   繁体   English

TypeScript:如何从类型中仅提取类型数组的键和值

[英]TypeScript: How can I extract from a type only the keys and values of type array

I'd like to come up with some conditional to extract only the properties from an object whose value is an array.我想提出一些条件来仅从值为数组的对象中提取属性。

For example:例如:

type Person = {
   name: string
   addresses: Address[]
   age: number
   phoneNumbers: PhoneNumber[]
}

PullOutArrays<Person> => {
   phoneNumbers: PhoneNumber[]
   addresses: Address[]
}

I attempted something like this to no avail:我尝试过这样的事情无济于事:

type PulledOutArrays<T extends Record<string, unknown>> = {
  [K in keyof T]: T[K] extends unknown[] ? T[K] : never
}

Cribbing from this GitHub issue :这个 GitHub 问题抄袭:

type FilteredKeys<T, U> = { [P in keyof T]: T[P] extends U ? P : never }[keyof T];

type FilteredProperties<T, U> = { [K in FilteredKeys<T, U>]: T[K]; };

type PullOutArrays<T> = FilteredProperties<T, unknown[]>;

type Person = {
  name: string
  addresses: string[]
  age: number
  phoneNumbers: number[]
}

type PersonKeys = FilteredKeys<Person, unknown[]>;

// "addresses" | "phoneNumbers"

type PersonArrays = PullOutArrays<Person>;

// {
//    addresses: string[];
//    phoneNumbers: number[];
// }

As you may have seen from your original attempt, what you end up with after mapping the conditional:正如您从最初的尝试中看到的那样,映射条件后您最终会得到什么:

{ [P in keyof T]: T[P] extends U ? P : never }

Is an interface containing all the property keys, but with the non-array types changed to never , apparently because TS does not initially check what the types assigned to property keys are.是一个包含所有属性键的接口,但非数组类型更改为never ,显然是因为 TS 最初不检查分配给属性键的类型是什么。 By adding an index on the end, you force the compiler to read the value of the property and ultimately omit it from the result.通过在末尾添加索引,您可以强制编译器读取属性的值并最终从结果中忽略它。

Using the union which is generated, you can then create a new mapped type from that union on the original interface.使用生成的联合,然后您可以从原始接口上的联合创建新的映射类型。

Came to a solution by following this answer :按照这个答案找到了解决方案:

type KeysOfType<T, U, B = false> = {
  [P in keyof T]: B extends true
    ? T[P] extends U
      ? U extends T[P]
        ? P
        : never
      : never
    : T[P] extends U
    ? P
    : never
}[keyof T]

type PickByType<T, U, B = false> = Pick<T, KeysOfType<T, U, B>>

type PickArrays<T> = PickByType<T, unknown[]>

@lawrence-witt 's answer is more elegant and should probably be used. @lawrence-witt的回答更优雅,可能应该使用。

Or if you are using TS 4.1+ , a more direct approach could be to remove keys by asserting the key as never based on the value type:或者,如果您使用的是TS 4.1+ ,更直接的方法可能是通过根据值类型断言键为never来删除键:

type OnlyArraysPerson = {
  [K in keyof Person as Person[K] extends unknown[] ? K : never]: Person[K]
}

To be more generic:更通用:

type OnlyArrays<T> = {
 [K in keyof T as T[K] extends unknown[] ? K : never]: T[K]
}

type ArrayPerson = OnlyArrays<Person>

Playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM