-
-
Notifications
You must be signed in to change notification settings - Fork 502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MergeDeep
type
#408
Add MergeDeep
type
#408
Conversation
Make sure you look at our existing "deep" types and that this new types handles all the cases handled by them. For example, type-fest/source/readonly-deep.d.ts Line 80 in 2f418db
|
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Replaces `ExtractType` with `ConditionalExcept` which already exists
Sorry, I'm not sure what I'm supposed to test. Can you give me a concrete example? |
source/merge-deep.d.ts
Outdated
|
||
/** | ||
`Unwrap` is like `Simplify` it flatten the type output to improve type hints shown in editors. | ||
Unfortunately Simplify does not support the case where the type cannot be flattened. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this handle types that cannot be flattened differently than Simplify
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can't iterate in the type then it can't be flattened, a function for example. Here is the simplest case TS Playground
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I suggest we just improve the Simplify
type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect, I will make a PR ;)
I gave you a concrete example: |
Some other examples:
|
At first I just wanted to contribute to a project I 💜 and improve my skills in the process by adding the SetProp type. While prototyping, I realized that I would need a Replace type to normalize the dotted paths. Then in several discussions I saw the need for the In any case I think I have to start all over again and define before going any further the needs for this type. If we want to go in the direction of lodash here is a non-exhaustive list cases I have been able to define: // If the first type (the destination) is [number, string, boolean] return the destination.
_.merge(42, 24); // 42
_.merge("42", "24"); // "42"
_.merge(true, false); // true
// [undefined, null, symbol, Set, Map] are always treated as empty objects regardless of location.
_.merge(undefined, null); // {}
_.merge(null, undefined); // {}
_.merge(Symbol(42), Symbol(24)); // {}
_.merge(new Set([42]), new Set([24])); // {}
_.merge(new Map([["life", 42]]), new Map([["life", 42]])); // {}
// If the first type is [Class, Function] return undefined.
_.merge(() => 42, {life:42}); // undefined
_.merge(Math.floor, {life:42}); // undefined
_.merge(Buffer, {life:42}); // undefined
// If the first type is an object and the second is an array, the array is treated as an indexed object.
_.merge({"id":42}, [42]); // {"0":42,"id":42}
_.merge(null, [42]); // {"0":42} // <- remeber null is treated as empty object
// If the first type is an array and the second is an object, the object is treated as an numerical indexed array stripping any string indexed properties.
_.merge([42], {"0":24,"id":42}); // [24]
_.merge([42], null); // [42]
// Instance of class is treated as an plain object.
class Foo {
constructor() {
this.id = "foo";
this.foo = true;
}
}
class Bar {
constructor() {
this.id = "bar";
this.bar = true;
}
}
_.merge(new Foo(), new Bar()); // {"id":"bar","foo":true,"bar":true} |
In fact I have thought wrongly, I should rather think in terms of types and not values. MergeDeep<{items: [1, 2, 3, 4, 5, 6]}, {items: ['a', 'b', 'c']}>;
// -> {items: ['a', 'b', 'c']}
// -> {items: string[]}
MergeDeep<{items: [1, 2, 3, 4, 5, 6]}, {items: ['a', 'b', 'c']}, {recurseIntoArrays: true}>;
// -> {items: [1, 2, 3, 4, 5, 6, 'a', 'b', 'c']}
// -> {items: (string|number)[]} Any suggestions? |
I agree with your examples.
👍
👍 |
This is really interesting. If you like you could provide some useful typings to @fastify/deepmerge :) |
@sindresorhus If you don't see anything to change, for me it's all good, the refactoring is done ;) |
source/merge-deep.d.ts
Outdated
Merge two types recursively into a new type. | ||
|
||
By default arrays are not supported, you have to explicitly enable it with the `recurseIntoArrays` option if you want it. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would explicitly document that arrays are concatenated type-wise.
@skarab42 Bump :) |
@sindresorhus I'm working on a better version (I hope), it will take a few more days. |
//=> never | ||
|
||
MergeDeep<[], [], {recurseIntoArrays: true}>; | ||
//=> [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just showing a couple of edge-cases. It needs to show a real-world example usage.
// Test MergeDeep inputs | ||
|
||
declare const signature1: MergeDeep<{}, {}>; // {} | ||
declare const signature2: MergeDeep<[], []>; // Never |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
declare const signature2: MergeDeep<[], []>; // Never | |
declare const signature2: MergeDeep<[], []>; //=> never |
I am closing this PR due to the new proposal #443. |
Merge two types recursively into a new type.
Properties set to
undefined
value are skipped whenstrict
option is set totrue
(default).Array and plain object properties are merged recursively.
@ilchenkoArtem @sindresorhus
SetProp
is comming soooon!