Skip to content
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

Using extendDictionary does not work well with nested namespaces. #741

Open
apatrida opened this issue Sep 14, 2023 · 2 comments
Open

Using extendDictionary does not work well with nested namespaces. #741

apatrida opened this issue Sep 14, 2023 · 2 comments
Labels
bug Something isn't working

Comments

@apatrida
Copy link

apatrida commented Sep 14, 2023

Version

5.26.2

Describe the bug

If you extend a dictionary (extendDictionary) and set a value in a nested namespace, it erases that whole namespace instead of just extending the one value. Details represented by the tests below.

It is unlikely you ever intend to erase values when extending a dictionary, you typically only override. So the default behavior is counter to that.

You can explicitly extend each nested namespace by hand extending, but only if you ignore the generated extendDictionary function that "hides" the original, and then use the original.

Reproduction

Taking the test cases for this utility method and adding this test case, it fails:

	simple: 'Hello',
	nested: { value: 'Hello nested' },
	nested2: { value1: "One value", value2: "Another value", value3: "And yet another value"},
	deeper: { nesting: { value1: "v1", value2: "v2" }}
}

test('nested extend with more complex', () => {
	const extended = extendDictionary(translationComplex, {
		simple: 'Hello extended',
		nested2: { value2: 'Another value extended' },
		deeper: { nesting: { value2: 'v2 extended'}}
	})
	assert.equal(extended, {
		simple: 'Hello extended',
		nested: { value: 'Hello nested' },
		nested2: { value1: "One value", value2: "Another value extended", value3: "And yet another value"},
		deeper: { nesting: { value1: "v1", value2: "v2 extended" } }
	});
})

You can actually do this to pass:


test('nested extend explicit at each level with more complex', () => {
	const extended = extendDictionary(translationComplex, {
		simple: 'Hello extended',
		nested2: extendDictionary(translationComplex.nested2, { value2: 'Another value extended' }),
		deeper: extendDictionary(translationComplex.deeper, { nesting:
				extendDictionary(translationComplex.deeper.nesting, { value2: 'v2 extended'})
		})
	})
	assert.equal(extended, {
		simple: 'Hello extended',
		nested: { value: 'Hello nested' },
		nested2: { value1: "One value", value2: "Another value extended", value3: "And yet another value"},
		deeper: { nesting: { value1: "v1", value2: "v2 extended" } }
	});
})

but this is really awkward. And is more so because the symbol extendDictionary is replaced in local generated code meaning you have to ignore that, and import the original version to make it work.

The original tests by @osdiab were not sufficient to be clear what was intended here.

Logs

No response

Config

No response

Additional information

No response

@apatrida apatrida added the bug Something isn't working label Sep 14, 2023
@apatrida
Copy link
Author

The fix is to change:

extend({}, base, part) as Translation

to:

extend(true, {}, base, part) as Translation

@apatrida
Copy link
Author

workaround is to add your own utility function:

export const initExtendLanguage =
  <TranslationType extends BaseTranslation>() =>
    <Base extends BaseTranslation | TranslationType, Translation extends Base>(
      base: Base,
      part: DeepPartial<ToGenericString<Translation>>,
    ): Translation =>
      extend(true, {}, base, part) as Translation

export const extendLanguage = initExtendLanguage()

and pnpm install just-extend@6.2.0 to use the same utility class already in the base library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant