基于另一个对象的数组来类型对象



我有一个下一个代码:

const arr = [
{
name: 'john',
age: '20'
},
{
name: 'anna',
age: '30'
}
]

现在我基于arr:

创建一个新对象
const obj = {} // {john:20,anna:30}
arr.forEach(o => obj[o.name]=o.age)

如何动态类型这个对象,需要这样的接口:

interface IObj {
john: number,
anna: number
}

您可以直接推断所有键和值,如下所示:

const arr = [
{
name: 'john',
age: '20'
},
{
name: 'anna',
age: '30'
}
]
type Elem = {
name: string;
age: `${number}`
}
type Callback<Item> =
(Item extends { name: infer Name, age: infer Age }
? (Name extends PropertyKey
? Record<Name, Age>
: never)
: never
)
type Reduce<List extends ReadonlyArray<any>, Acc extends Record<string, `${number}`> = {}> =
(List extends []
? Acc
: (List extends [infer Head, ...infer Tail]
? Reduce<Tail, Acc & Callback<Head>>
: never)
)
const builder = <
Name extends string,
Age extends `${number}`,
Item extends { name: Name, age: Age },
List extends ReadonlyArray<Item>
>(list: [...List]) =>
list.reduce((acc, elem) => ({
...acc,
[elem.name]: elem.age
}), {} as Reduce<List>)
const result = builder([
{
name: 'john',
age: '20'
},
{
name: 'anna',
age: '30'
}
])
result.anna // 30
result.john // 20

游乐场

我使用了几个额外的泛型,Name,Age,ItemList来推断每个属性。把它看作是一种解构。如果你想在TypeScript中推断出一些嵌套的属性,你应该为它创建generic。

Reduce-是实用程序类型。它递归地迭代参数,并折叠每个元素。就像你在实现中做的那样。除了,你用的是forEach而我用的是reduce。这只是个人喜好的问题。

如果你认为上面的版本是一个开销或过度工程,你可以使用这个:

type Elem = {
name: string;
age: `${number}`;
}
const builder = <
List extends ReadonlyArray<Elem>
>(list: List) =>
list.reduce((acc, elem) => ({
...acc,
[elem.name]: elem.age
}), {} as Record<string, `${number}`>)
const result = builder([
{
name: 'john',
age: '20'
},
{
name: 'anna',
age: '30'
}
])
result.anna // 30
result.john // 20

相关内容

  • 没有找到相关文章

最新更新