如何根据类型化对象数组中的键推断类型?
How can infer a type based on a key from an array of typed objects?
我正在尝试使用其中一个重复出现的(和必需的)键创建一个基于对象数组的类型,但是 typescript 没有按照我期望的方式处理 Array.map()
:
const list = [
{
_id: 'foo1'
},
{ _id: 'foo2' }
] as const
const listIds = list.map(listValue => listValue._id)
我希望 listIds
被推断为 ['foo1', 'foo2']
,但被视为 ("foo1" | "foo2")[]
。这对我来说没有意义,因为 Array.map
到 return 一个与原始数组大小不同的数组是不可能的。
还有其他方法可以获得我正在寻找的结果吗?
PS。请参阅 TypeScript Playground 示例 here。
对于获取特定键值的这种特定情况,可以使用辅助函数:
const mapByKey = <A extends readonly unknown[], K extends keyof A[number]>(
array: A,
key: K
// the -readonly ensures the return type isn't readonly even if the
// input array is
): {-readonly [P in keyof A]: A[P][K]} =>
array.map((x: A[number]) => x[key]) as {-readonly [P in keyof A]: A[P][K]}
// ['foo1', 'foo2']
const listIds = mapByKey(list, '_id')
但是,我认为没有一种简单的方法可以将此概括为任何类型的函数。
我们真正想要的:
declare const map: <A extends readonly unknown[], F>(
array: A,
fn: <T extends A[number]>(x: T) => F<T>
): {-readonly [K in keyof A]: F<A[K]>}
// with your example F would be like a generic type like
// type F<T> = T['_id']
但是,这不会编译为 TypeScript lacks higher-kinded types。在 TypeScript 中有各种 hacks 可以模拟这个,但它们使用起来很麻烦,我个人认为这不值得解决这个问题。
我正在尝试使用其中一个重复出现的(和必需的)键创建一个基于对象数组的类型,但是 typescript 没有按照我期望的方式处理 Array.map()
:
const list = [
{
_id: 'foo1'
},
{ _id: 'foo2' }
] as const
const listIds = list.map(listValue => listValue._id)
我希望 listIds
被推断为 ['foo1', 'foo2']
,但被视为 ("foo1" | "foo2")[]
。这对我来说没有意义,因为 Array.map
到 return 一个与原始数组大小不同的数组是不可能的。
还有其他方法可以获得我正在寻找的结果吗?
PS。请参阅 TypeScript Playground 示例 here。
对于获取特定键值的这种特定情况,可以使用辅助函数:
const mapByKey = <A extends readonly unknown[], K extends keyof A[number]>(
array: A,
key: K
// the -readonly ensures the return type isn't readonly even if the
// input array is
): {-readonly [P in keyof A]: A[P][K]} =>
array.map((x: A[number]) => x[key]) as {-readonly [P in keyof A]: A[P][K]}
// ['foo1', 'foo2']
const listIds = mapByKey(list, '_id')
但是,我认为没有一种简单的方法可以将此概括为任何类型的函数。
我们真正想要的:
declare const map: <A extends readonly unknown[], F>(
array: A,
fn: <T extends A[number]>(x: T) => F<T>
): {-readonly [K in keyof A]: F<A[K]>}
// with your example F would be like a generic type like
// type F<T> = T['_id']
但是,这不会编译为 TypeScript lacks higher-kinded types。在 TypeScript 中有各种 hacks 可以模拟这个,但它们使用起来很麻烦,我个人认为这不值得解决这个问题。