Append to Object
挑战
实现一个向接口添加新字段的类型。该类型接受三个参数。输出应该是一个带有新字段的对 象。
例如:
type Test = { id: "1" };
type Result = AppendToObject<Test, "value", 4>; // expected to be { id: '1', value: 4 }
解答
当我们试图改变 TypeScript 中的对象接口时,通常交叉(intersection)类型会很有帮
助。这一挑战也不例外。我试着写了一个类型,它接受整个T
和一个带有新属性的对象:
type AppendToObject<T, U, V> = T & { [P in U]: V };
不幸的是,这个方案不能满足测试。它们期望的是一个普通(flat)类型而不是交叉
(intersection)类型。因此我们需要返回一个对象类型,其中包含所有属性和我们的新属
性。我将从映射T
的属性开始:
type AppendToObject<T, U, V> = { [P in keyof T]: T[P] };
现在,我们需要在T
的属性中添加新属性U
。这里有一个诀窍。没有什么可以阻止你将联
合传递给in
操作符:
type AppendToObject<T, U, V> = { [P in keyof T | U]: T[P] };
这样,我们就能得到T
的所有属性加上属性U
,这正是我们需要的。现在让我们通过
在U
上添加一个约束来修复小错误:
type AppendToObject<T, U extends string, V> = { [P in keyof T | U]: T[P] };
现在 TypeScript 唯一不能处理的是P
可能不在T
中,因为P
是T
和U
的并集。我们
需要处理下这种情况,如果P
来自于T
,我们取T[P]
,否则取V
:
type AppendToObject<T, U extends string, V> = {
[P in keyof T | U]: P extends keyof T ? T[P] : V;
};
评论