如何在 Typescript 中输入 Object.entries() 和 Object.fromEntries?

Posted

技术标签:

【中文标题】如何在 Typescript 中输入 Object.entries() 和 Object.fromEntries?【英文标题】:How can I get typed Object.entries() and Object.fromEntries in Typescript? 【发布时间】:2021-10-31 07:36:00 【问题描述】:

当我在 typescript 中为我的 typed/const entries 数组或 objt 对象使用 Object.fromEntries(entries)Object.entires(obj) 时,我将类型丢失为 any 或广泛类型。

在某些情况下,我可以手动分配泛型类型(例如Record<string, number>),但设置每对/键的类型很繁琐。

这是我想要的一个例子。

Typed Object.fromEntries(entries)

const myArrayOfPairs = [["a", 5], ["b", "hello"], ["c", false]] as const;

// The type of the following is "any"
const myTypelessObject = Object.fromEntries(myArrayOfPairs);

// I want the type of this one to be:  a: 5; b: "hello"; c: false; 
const myTypedObject = createTypedObjectFromEntries(myArrayOfPairs); 

类型化 Object.entries(obj)

const myOldObject = 
    x: 6,
    y: "apple",
    z: true
;

// The type of the following is [string, string | number | boolean][]
const myEntries = Object.entries(myOldObject);

// I want the type of this one to be more specific.
// i.e.: (["x", number] | ["y", string] | ["z", boolean])[]
const myTypedEntries = getTypedObjectEntries(myOldObject);

【问题讨论】:

【参考方案1】:

Object.Entries(obj) -- 对象到键值对数组

这个比较简单。使用[K in keyof OBJ_T]可以得到key,OBJ_T[K]给出相对值。

这是一个简单的实现:

// ~~~~~~~~~~~~~~~~~~~~~~~~ Utils ~~~~~~~~~~~~~~~~~~~~~~~~

type ObjectType = Record<PropertyKey, unknown>;
type PickByValue<OBJ_T, VALUE_T> // From https://***.com/a/55153000
    = Pick<OBJ_T,  [K in keyof OBJ_T]: OBJ_T[K] extends VALUE_T ? K : never [keyof OBJ_T]>;
type ObjectEntries<OBJ_T> // From https://***.com/a/60142095
    =  [K in keyof OBJ_T]: [keyof PickByValue<OBJ_T, OBJ_T[K]>, OBJ_T[K]] [keyof OBJ_T][];

// ~~~~~~~~~~~~~~~~~~~~ Typed Function ~~~~~~~~~~~~~~~~~~~~

function getTypedObjectEntries<OBJ_T extends ObjectType>(obj: OBJ_T): ObjectEntries<OBJ_T> 
    return Object.entries(obj) as ObjectEntries<OBJ_T>;


// ~~~~~~~~~~~~~~~~~~~~~~~~~ Test ~~~~~~~~~~~~~~~~~~~~~~~~~

const myOldObject = 
    x: 6,
    y: "apple",
    z: true
;

const myTypelessEntries = Object.entries(myOldObject); // type: [string, string | number | boolean][]

const myTypedEntries = getTypedObjectEntries(myOldObject);
type myTypedEntiresType = typeof myTypedEntries;  // type: (["x", number] | ["y", string] | ["z", boolean])[]

TS Playground。 注意,您需要 es2019 成为 Configs 中的目标。

Object.fromEntries(entries) -- 对象的键值对数组

这是一项更具挑战性的任务。

您需要先使用infer 提取内部数组对,然后使用常见的UnionToIntersection 实用程序类型合并结果。

这是我能想到的最好的:

// ~~~~~~~~~~~~~~~~~~~~~~~~ Utils ~~~~~~~~~~~~~~~~~~~~~~~~

// Data Types
type EntriesType = [PropertyKey, unknown][] | ReadonlyArray<readonly [PropertyKey, unknown]>;

// Existing Utils
type DeepWritable<OBJ_T> =  -readonly [P in keyof OBJ_T]: DeepWritable<OBJ_T[P]> ;
type UnionToIntersection<UNION_T> // From https://***.com/a/50375286
    = (UNION_T extends any ? (k: UNION_T) => void : never) extends ((k: infer I) => void) ? I : never;

// New Utils
type UnionObjectFromArrayOfPairs<ARR_T extends EntriesType> =
    DeepWritable<ARR_T> extends (infer R)[] ? R extends [infer key, infer val] ?  [prop in key & PropertyKey]: val  : never : never;
type MergeIntersectingObjects<ObjT> = [key in keyof ObjT]: ObjT[key];
type EntriesToObject<ARR_T extends EntriesType> = MergeIntersectingObjects<UnionToIntersection<UnionObjectFromArrayOfPairs<ARR_T>>>;

// ~~~~~~~~~~~~~~~~~~~~~ Typed Functions ~~~~~~~~~~~~~~~~~~~~~

function createTypedObjectFromEntries<ARR_T extends EntriesType>(arr: ARR_T): EntriesToObject<ARR_T> 
    return Object.fromEntries(arr) as EntriesToObject<ARR_T>;


// ~~~~~~~~~~~~~~~~ Test for entries->object ~~~~~~~~~~~~~~~~~

const myArrayOfPairs = [["a", 5], ["b", "hello"], ["c", false]] as const;

const myTypelessObject = Object.fromEntries(myArrayOfPairs); // type: any

const myTypedObject = createTypedObjectFromEntries(myArrayOfPairs);
type myTypedObjectType = typeof myTypedObject; // type:  a: 5; b: "hello"; c: false; 

TS Playground

【讨论】:

以上是关于如何在 Typescript 中输入 Object.entries() 和 Object.fromEntries?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TypeScript 中获取 JSON 文件上的 Object.keys 时设置类型?

使用 Typescript 在 JSON 中搜索字符串

ReactJs 和 Typescript,使用 TSX 时如何更改对象内变量的状态

TypeScript 中 'object' 、 和 Object 之间的区别

Typescript reactjs无法将道具传播到输入标签

在 TypeScript 中键入 rest 运算符对象