voodoocreation / ts-deepmerge Goto Github PK
View Code? Open in Web Editor NEWA TypeScript deep merge function with automatically inferred types.
A TypeScript deep merge function with automatically inferred types.
#0 90.24 error [email protected]: The engine "node" is incompatible with this module. Expected version ">=16". Got "14.20.0"
We were running 2.0.1 on Google cloud with node 14 up until last rebuild which somehow replaced 2.0.1 with 2.0.6 through firebase-functions-test.
Forgive me if this isn't an issue but I would expect TS to prevent me from merging two non-overlapping objects.
If I have a variable of type Blah
interface Blah {
key: string;
value: string;
}
const source: Blah = {
key: 'abc',
value: 'def',
};
and I try to merge it with something which is not type Blah
, I'd expect to see an error.
merge(source, { key: 'boop', ruh: 'roh' });
This is allowed, however. If I try to tell merge
what types to expect, I get a different error:
merge<Blah>(source, { key: 'boop', ruh: 'roh' });
// TS2344: Type 'Blah' does not satisfy the constraint 'IObject[]'.
// Type 'Blah' is missing the following properties from type 'IObject[]': length, pop, push, concat, and 31 more
Using the normal deepmerge
package gives me what I'd expect though.
merge<Blah>(source, { key: 'boop', ruh: 'roh' });
// TS2345: Argument of type '{ key: string; ruh: string; }' is not assignable to parameter of type 'Partial<Blah>'.
// Object literal may only specify known properties, and 'ruh' does not exist in type 'Partial<Blah>'.
Why is the key length a reserved property on IObject? I cannot find a reason why -- hoping for either clarify, or removal :) I am running into issues with my object that has a property called length
I forked the project today and added options as I needed them for a project of mine.
interface MergeOptions {
mergeArrays?: boolean;
merger?: Merger;
}
type Merger = (a: any, b: any, defaultMerger: (a: any, b: any) => any, options: { mergeArrays: boolean }) => any;
My changes allow to configure arrays being merged or replaced and allows to provide a default merger to provide additional custom logic. The default merger can be called from within the merger to allow for easy extensibility while keeping basic functionality working.
I made too many code changes to the fork already, but the changes could be ported over to this project if desired - You can see this issue as an Idea/Feature Request of some sort.
Tell me what you think ^^
Is there a way to prevent removing of duplicates in a merged array?
Example
import merge from "ts-deepmerge";
var color = {
color: [
"#FC4",
"#FC4",
"#FC4",
"#F00",
"#F00",
"#44F",
"#44F",
"#44F",
"#000",
"#000",
"#000",
"#44F",
"#44F",
"#44F",
"#44F"
]
}
var other = {
color: []
}
console.log(merge(color, other))
I expect the above to output
{
color: [
'#FC4', '#FC4', '#FC4',
'#F00', '#F00', '#44F',
'#44F', '#44F', '#000',
'#000', '#000', '#44F',
'#44F', '#44F', '#44F'
]
}
but instead it outputs
{ color: [ '#FC4', '#F00', '#44F', '#000' ] }
Hi
export type Config = {
presets?: {
/** @default false */
flexGrid?: boolean
/** @default false */
fontWeightRegular?: boolean
/** @default true */
moreDefaultValues?: boolean
/** @default false */
screenToDynamicScreen?: boolean
}
utilities?: {
/** @default true */
bgGrid?: boolean
/** @default true */
bgRadial?: boolean
/** @default true */
dir?: boolean
/** @default true */
drag?: boolean
/** @default true */
flip?: boolean
/** @default true */
hideShow?: boolean
/** @default true */
inputResets?: boolean
/** @default true */
insetCenter?: boolean
/** @default true */
overflowUnset?: boolean
/** @default true */
tapHighlight?: boolean
}
variants?: {
/** @default true */
notVariants?: boolean
}
}
const defaultConfig = {
presets: {
flexGrid: false,
fontWeightRegular: false,
moreDefaultValues: true,
screenToDynamicScreen: false,
},
utilities: {
bgGrid: true,
bgRadial: true,
dir: true,
drag: true,
flip: true,
hideShow: true,
inputResets: true,
insetCenter: true,
overflowUnset: true,
tapHighlight: true,
},
variants: {
notVariants: true,
},
} satisfies Config
export default (userConfig?: Config) => {
const config = merge(defaultConfig, userConfig || {})
}
The issue is, TS shows me this error, for example, fontWeightRegular
in config.presets?.fontWeightRegular
can be undefined
.
It's expected that fontWeightRegular
will always have a value. But TS doesn't know that.
I want to merge the default options with the same options (with custom values) added by the user.
Hi. Great library!
I seem to have come across a strange issue with the object comparison. For example, the prototype comparison doesn't work when using Object.create
, I came across this issue with some default exports from a CJS module, which I haven't managed to repro fully, but this seems to be the crux of the problem:
Object.getPrototypeOf(Object.create({bool: true})) === Object.prototype // false
Was there a specific reason for including prototype comparison in isObject
. Could it be simplified to just typeof
comparison, for example the isObject
lodash function is implemented as so:
function isObject(value) {
const type = typeof value
return value != null && (type === 'object' || type === 'function')
}
Consider this snippet:
interface Foo {
x: number;
y: number;
}
const a: Foo = { x: 1, y: 2 };
const b: Partial<Foo> = { x: 3 };
const merged = merge(a, b);
In this snippet, I would expect the values to get merged. They are. So far so good. But I would expect the same for the types. Merging a required and optional member of the same name, should result in that type becoming a required one. That is, among others, what I think merging types should be about.
It should be more than just simply "orring" them together.
Hey, thanks you work on this package.
Do you mind adding a license?
Hi!
This might be true as you could specifically set a value to be undefined and that would override it, but if there was an option to avoid this, the type could return the full type rather than a partial version.
This option would make it work more ideally for cases like the example below where you'd want to merge default options with some configurations.
interface Theme {
button: {
background: string;
color: string;
}
}
const defaultTheme: Theme = {
button: {
background: '#a1a1a1',
color: '#dedede'
}
}
const themeConfig: DeepPartial<Theme> = {
button: {
color: '#fff'
}
}
/**
* Everything is possibly undefined.
* While I'd wish for it to ignore undefined values from themeConfig,
* and return the full type for Theme, not DeepPartial<Theme>
*/
const theme = merge(defaultTheme, themeConfig)
When ts-deepmerge is used in a Webpack 5 project and the project is built, Webpack generates the following warning:
Failed to parse source map from '«path»\node_modules\ts-deepmerge\src\index.ts' file: Error: ENOENT: no such file or directory, open '«path»\node_modules\ts-deepmerge\src\index.ts'
The fix is easy: change "sourceMap": true,
to "sourceMap": false,
in tsconfig.json
.
The types only intersection instead of deep merged.
May helpful: https://stackoverflow.com/questions/60114191/typescript-union-type-to-deep-intersection-of-optional-values-difficulty-leve
Does it bias towards the first or last or error?
Currently the library is pinned to "typescript": "^4.9.4"
. Can we upgrade the dep to allow for 5?
How to replicate:
const a = [ { a: 1 } ]
const b = [ { a: 2 } ]
const c = merge.withOptions({ mergeArrays: false }, a, b)
console.log(c)
returns
{ '0': { a: 2 } }
expected:
[ { a: 2 } ]
The compiled js can't use
{
default: [Function: merge] {
options: { mergeArrays: true },
withOptions: [Function (anonymous)]
}
}
TypeError: deepMerge is not a function
Hi, I'm encountering an issue when merging objects that have ES6-class-valued properties that have private properties on them. An example:
class A {
constructor(private readonly b: number) {}
}
interface C {
a: A;
}
const d: C = merge({ a: new A(1) }, { a: new A(2) });
This example does not compile with typescript 5.1.6, @tsconfig/node20/tsconfig.json, and ts-deepmerge > 4.0.0 (it works <= 4.0.0).
I can see both sides of this being a bug or not - curious what you think. If you don't consider this a bug, do you have any ideas about a workaround?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.