英文:
Append an extra member to an object - type intersection vs iteration approach
问题
以下是翻译好的内容:
这是一个问题:AppendToObject。我对这个问题的第一直觉是使用类型交集,例如,
type AppendToObject<T, U extends PropertyKey, V> = T & {[P in U]: V}
然而,这个解决方案不能通过测试用例。
type test1 = {
key: 'cat'
value: 'green'
}
type testExpect1 = {
key: 'cat'
value: 'green'
home: boolean
}
type test2 = {
key: 'dog' | undefined
value: 'white'
sun: true
}
type testExpect2 = {
key: 'dog' | undefined
value: 'white'
sun: true
home: 1
}
type test3 = {
key: 'cow'
value: 'yellow'
sun: false
}
type testExpect3 = {
key: 'cow'
value: 'yellow'
sun: false
moon: false | undefined
}
// 引用自
// https://github.com/type-challenges/type-challenges/blob/main/utils/index.d.ts
type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false
type Expect<T extends true> = T
type cases = [
Expect<Equal<AppendToObject<test1, 'home', boolean>, testExpect1>>,
Expect<Equal<AppendToObject<test2, 'home', 1>, testExpect2>>,
Expect<Equal<AppendToObject<test3, 'moon', false | undefined>, testExpect3>>,
]
所以我改成了迭代的方法,它通过了所有的测试用例。
type AppendToObject<T, U extends PropertyKey, V> = {[P in U | keyof T ]: P extends keyof T ? T[P] : V}
我没有看到交集方法有什么问题,因为如果我使用它来定义一个对象,也必须指定额外的参数。解决方案是否因为 Equal
的实现方式而无法通过测试?或者,这两种方法之间是否存在我不知道的其他细微差别?
英文:
Here is the question: AppendToObject. My first intuition to the question was to use type intersection, e.g,
type AppendToObject<T, U extends PropertyKey, V> = T & {[P in U]: V}
However, that solution doesn't pass the testcases.
type test1 = {
key: 'cat'
value: 'green'
}
type testExpect1 = {
key: 'cat'
value: 'green'
home: boolean
}
type test2 = {
key: 'dog' | undefined
value: 'white'
sun: true
}
type testExpect2 = {
key: 'dog' | undefined
value: 'white'
sun: true
home: 1
}
type test3 = {
key: 'cow'
value: 'yellow'
sun: false
}
type testExpect3 = {
key: 'cow'
value: 'yellow'
sun: false
moon: false | undefined
}
// reference from
// https://github.com/type-challenges/type-challenges/blob/main/utils/index.d.ts
type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false
type Expect<T extends true> = T
type cases = [
Expect<Equal<AppendToObject<test1, 'home', boolean>, testExpect1>>,
Expect<Equal<AppendToObject<test2, 'home', 1>, testExpect2>>,
Expect<Equal<AppendToObject<test3, 'moon', false | undefined>, testExpect3>>,
]
So I changed to the iteraction approach and it passes all the testcases.
type AppendToObject<T, U extends PropertyKey, V> = {[P in U | keyof T ]: P extends keyof T ? T[P] : V}
I'm not seeing anything wrong with the intersection approach, as if I type an object with it, it's also compulsory to specify the extra argument. Does the solution fail the tests just because of how Equal
is implemented? Or, is there any other nuances between these two approaches that I'm not aware?
答案1
得分: 1
AppendToObject
看起来结果类型是正确的。所以我怀疑问题在于Equal
如何比较这些类型。示例:
type test1 = {
key: 'cat';
value: 'green';
};
type testExpect1 = {
key: 'cat';
value: 'green';
home: boolean;
};
// type Result = test1 & {
// home: boolean;
// }
type Result = AppendToObject<test1, 'home', boolean>
所以testExpect1
没有交集,但属性直接在一个对象中。
这可以通过使用type-samurai包中的Prettify实用类型来修复。简化版本:
type Prettify<T> = T extends infer R
? {
[K in keyof R]: R[K];
}
: never;
Prettify
重新映射类型,导致移除交集并使其更易读。
测试:
type AppendToObject<T, U extends PropertyKey, V> = Prettify<
T & { [P in U]: V }
>;
// type Result = {
// key: 'cat';
// value: 'green';
// home: boolean;
// }
type Result = AppendToObject<test1, 'home', boolean>;
英文:
The result types for the AppendToObject
looks correct. So I suspect the issue is with how the Equal
compares the types. Example:
type test1 = {
key: 'cat';
value: 'green';
};
type testExpect1 = {
key: 'cat';
value: 'green';
home: boolean;
};
// type Result = test1 & {
// home: boolean;
// }
type Result = AppendToObject<test1, 'home', boolean>
So the testExpect1
has no intersection, but the property is directly in one object.
This can be fixed by using the Prettify utility type from the type-samurai package. Simplified version:
type Prettify<T> = T extends infer R
? {
[K in keyof R]: R[K];
}
: never;
Prettify
remaps the type which causes to remove the intersection and make the more readable.
Testing:
type AppendToObject<T, U extends PropertyKey, V> = Prettify<
T & { [P in U]: V }
>;
// type Result = {
// key: 'cat';
// value: 'green';
// home: boolean;
// }
type Result = AppendToObject<test1, 'home', boolean>;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论