1

I am using a mapped type in my source, that I am reusing throughout my project:

type StringUnion = string | string[];
type StringUnionMap = { [key: string]: StringUnion };

I have to combine two of these maps into one map that contains the entries of both:

let map1: StringUnionMap = { "key1": "value1", "key2": "value2" };
let map2: StringUnionMap = { "key3": [ "value3a", "value3b" ] };

I can of course achieve what I want in a loop like this:

let combinedMap: StringUnionMap = {};
for (let key in map1) {
    combinedMap[key] = map1[name];
}
for (let key in map2) {
    combinedMap[key] = map2[name];
}

I find this way a bit clumsy and verbose. Is there any more concise way to combine my two maps?

I have tried this, but that does not compile transpile:

let combinedMap: StringUnionMap = new StringUnionMap( [ map1, map2 ] );

The respective JavaScript solution with Object.assign does not work, because I am targeting ES5 with noImplicitAny turned on. Therefore Object.assign is not available to me.

Sefe
  • 13,731
  • 5
  • 42
  • 55
  • Why are you calling these "maps"? They are objects. Also, why do you think this is TypeScript-related? TypeScript is not the language, it's just a type layer. This is just regular old JS (or ES6) question. –  Dec 14 '16 at 17:33
  • Possible duplicate of [How can I merge properties of two JavaScript objects dynamically?](http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically) –  Dec 14 '16 at 17:36
  • Calm down. Please consult the answers, which suggest `Object.assign` or its equivalent, which is a pure ES6 construct. –  Dec 14 '16 at 18:21
  • It's not how "I want to call it". It's how **everybody** calls it, because that is the **correct** way to call it. There is an even better reason for not calling what you have a "map", because "map" has an extremely specific meaning in the JS world (yes, it **is** JS), which is a value of type `Map`. Anyway, your "construct" **does** exist in JS. All you have done is applied TS typing to a JS object, which doesn't change the fact that it is a JS object. I suggest you go back and carefully study the role of TS in the language ecosystem. –  Dec 14 '16 at 18:25
  • From a previous version of this question: *Does [tag:typescript] provide me with a more concise way to combine my two maps?* TypeScript provides no new language features or new functionality. It's ES6, plus selected ES7+ features that are sufficiently advanced in the TC39 process, with typing. It adds new syntax, but that new syntax is strictly limited to specifying and handling typing information. It knows how to transpile to ES3/ES5/ES6, but in that regard is identical to Babel--yet no one would say the Babel is a language. It takes one form of JS and transpiles it into a different form. –  Dec 14 '16 at 19:04
  • (cont'd) Depending on the version of JS it is targeting, it may transpile certain constructs such as `...foo` into code that works in ES5, or it may even invoke run-time routines, but that does not affect that fact that it is precisely a (1) typed version of the JS language, with type checking and (2) a transpiler exactly like Babel. You say "it does not mean that TS is JS"; actually, TS **is exactly** JS, with syntactic extensions for declaring, asserting, and checking types; as they themselves call it, a "typed superset of JS". –  Dec 14 '16 at 19:09

2 Answers2

6

Typescript 2.1 allows you to merge the objects using spread syntax:

let combinedMap: StringUnionMap = {...map1, ...map2};

Generated code will use Object.assign function if avaliable or provide polyfill instead:

var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
var map1 = { "key1": "value1", "key2": "value2" };
var map2 = { "key3": ["value3a", "value3b"] };
var combinedMap = __assign({}, map1, map2);
Aleksey L.
  • 35,047
  • 10
  • 74
  • 84
0

Typescript doesn't give you functionality like that, but javascript has the Object.assign function which does pretty much what you're looking for:

type StringUnion = string | string[];
type StringUnionMap = { [key: string]: StringUnion };

let map1: StringUnionMap = { "key1": "value1", "key2": "value2" };
let map2: StringUnionMap = { "key3": ["value3a", "value3b"] };

let combinedMap: StringUnionMap = Object.assign({}, map1, map2);
console.log(combinedMap); // Object {key1: "value1", key2: "value2", key3: Array[2]}

(code in playground)

Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • 2
    Why "pretty much"? Isn't it "exactly"? –  Dec 14 '16 at 17:37
  • I have tried this option and it doesn't work. [The reason is that I am targeting ES5.](http://stackoverflow.com/questions/38860161/using-typescript-and-object-assign-gives-me-an-error-property-assign-does-no) – Sefe Dec 14 '16 at 19:32
  • 1
    `Object.assign` does not verify types integrity. See [code in playground](https://www.typescriptlang.org/play/index.html#code/C4TwDgpgBAysBOBLAdgcwKrMQe2VAvFAM4IqpQA+xpaA2gLoDcAUKJLDRlrgLICGYAlADeUWgGsIIAFzUkaerLjyuOPAF8WzADYRgUALYCAjEs6Y1-QYVEAiSSGO3ZtgG59tAVwhOANFHspACZnAPcvCBCoTR09QwEgoTsHAGZQgE5M6K1dfQBjbAMAIxQIABMrMxULXgEhAHkigCsIPOAAOj4iIkRUZAAKYXV-IzBjEYSASkYoAHpZqDLsCCIoZGx9YAALeGwAdyg+PAh4XfgoAEIr5gLkImxddu1sVH6C4tKKgWm5hcaWtoiBymMIebx+KAOIIucLeEL+VKyTLpdRAA) – pumbo Jul 21 '19 at 08:10