How to make two enums have the same keys? - javascript

I have these two enums:
enum foo {
bar,
baz
}
enum fiz {
...
}
How can I make sure, that fiz has the same keys as foo? I tried adding an interface, but no luck with assigning.

You can use a map.
enum foo {
bar,
baz,
}
const fiz = new Map<foo, string>([
[foo.bar, 'value1'],
[foo.baz, 'value2'],
]);
OR you can do something like this
enum Foo {
A = "ActivityCode.Foo.A",
B = "ActivityCode.Foo.B",
C = "ActivityCode.Foo.C",
}
enum Bar {
A = "ActivityCode.Bar.A",
B = "ActivityCode.Bar.B",
C = "ActivityCode.Bar.C",
}
enum Baz {
A = "ActivityCode.Baz.A",
B = "ActivityCode.Baz.B",
C = "ActivityCode.Baz.C",
}
const ActivityCode = {
Foo,
Bar,
Baz,
};
console.log(ActivityCode.Foo.A);
reference

Based on your comment, I think this is approach will work well for you:
TS Playground
const keys = ['foo', 'bar', 'baz'] as const;
type Key = typeof keys[number]; // "foo" | "bar" | "baz"
type ObjectWithSameKeys<ValueType> = Record<Key, ValueType>;
const labels: ObjectWithSameKeys<number> = {
foo: 1,
bar: 2,
baz: 3,
};
const names: ObjectWithSameKeys<string> = {
foo: 'one',
bar: 'two',
baz: 'three',
};

Related

How to give a class all the values of a created object in Javascript

If within a class constructor and I lookup an object that contains many values, how can I make it so that class will obtain all those values?
For example, if this is my object:
const myObject = {
a: 1,
b: 2,
c: 3
}
This is my class:
class MyClass {
constructor() {
const object = createMyObject(); // This function returns the above myObject
}
}
Now, how do I make it so MyClass has all the values of myObject so I can do something like:
const class = new MyClass();
console.log(class.a);
// 1
Iterate over the object with Object.entries and assign the key/value pairs to the class.
function createMyObject() {
return {
a: 1,
b: 2,
c: 3
};
}
class MyClass {
constructor() {
const object = createMyObject();
const entries = Object.entries(object);
for (const [key, value] of entries) {
this[key] = value;
}
}
}
const o = new MyClass();
console.log(o.a);
console.log(o.b);
console.log(o.c);
you can do this:
function createMyObject(){
return {
a:1,
b:2,
c:3
}
}
class MyClass{
constructor(){
Object.assign(this,createMyObject())
}
}
const res = new MyClass();
console.log(res.a)
console.log(res.b)
console.log(res.c)

How to use ES6 Object Spread Operator to assign arguments passed to a function as object properties? [duplicate]

For example if I have two objects:
var foo = {
x: "bar",
y: "baz"
}
and
var oof = {}
and I wanted to transfer the x and y values from foo to oof. Is there a way to do that using the es6 destructuring syntax?
perhaps something like:
oof{x,y} = foo
While ugly and a bit repetitive, you can do
({x: oof.x, y: oof.y} = foo);
which will read the two values of the foo object, and write them to their respective locations on the oof object.
Personally I'd still rather read
oof.x = foo.x;
oof.y = foo.y;
or
['x', 'y'].forEach(prop => oof[prop] = foo[prop]);
though.
IMO this is the easiest way to accomplish what you're looking for:
let { prop1, prop2, prop3 } = someObject;
let data = { prop1, prop2, prop3 };
// data === { prop1: someObject.prop1, ... }
Basically, destructure into variables and then use the initializer shorthand to make a new object. No need for Object.assign
I think this is the most readable way, anyways. You can hereby select the exact props out of someObject that you want. If you have an existing object you just want to merge the props into, do something like this:
let { prop1, prop2, prop3 } = someObject;
let data = Object.assign(otherObject, { prop1, prop2, prop3 });
// Makes a new copy, or...
Object.assign(otherObject, { prop1, prop2, prop3 });
// Merges into otherObject
Another, arguably cleaner, way to write it is:
let { prop1, prop2, prop3 } = someObject;
let newObject = { prop1, prop2, prop3 };
// Merges your selected props into otherObject
Object.assign(otherObject, newObject);
I use this for POST requests a lot where I only need a few pieces of discrete data. But, I agree there should be a one liner for doing this.
EDIT: P.S. -
I recently learned you can use ultra destructuring in the first step to pull nested values out of complex objects! For instance...
let { prop1,
prop2: { somethingDeeper },
prop3: {
nested1: {
nested2
}
} = someObject;
let data = { prop1, somethingDeeper, nested2 };
Plus, you could use spread operator instead of Object.assign when making a new object:
const { prop1, prop2, prop3 } = someObject;
let finalObject = {...otherObject, prop1, prop2, prop3 };
Or...
const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
No, destructuring does not support member expressions in shorthands but only plain propertynames at the current time. There have been talks about such on esdiscuss, but no proposals will make it into ES6.
You might be able to use Object.assign however - if you don't need all own properties, you still can do
var foo = …,
oof = {};
{
let {x, y} = foo;
Object.assign(oof, {x, y})
}
Other than Object.assign there is the object spread syntax which is a Stage 2 proposal for ECMAScript.
var foo = {
x: "bar",
y: "baz"
}
var oof = { z: "z" }
oof = {...oof, ...foo }
console.log(oof)
/* result
{
"x": "bar",
"y": "baz",
"z": "z"
}
*/
But to use this feature you need to use stage-2 or transform-object-rest-spread plugin for babel. Here is a demo on babel with stage-2
BabelJS plugin
If you are using BabelJS you can now activate my plugin babel-plugin-transform-object-from-destructuring (see npm package for installation and usage).
I had the same issue described in this thread and for me it was very exhausting when you create an object from a destructuring expression, especially when you have to rename, add or remove a property. With this plugin maintaining such scenarios gets much more easier for you.
Object example
let myObject = {
test1: "stringTest1",
test2: "stringTest2",
test3: "stringTest3"
};
let { test1, test3 } = myObject,
myTest = { test1, test3 };
can be written as:
let myTest = { test1, test3 } = myObject;
Array example
let myArray = ["stringTest1", "stringTest2", "stringTest3"];
let [ test1, , test3 ] = myArray,
myTest = [ test1, test3 ];
can be written as:
let myTest = [ test1, , test3 ] = myArray;
It's totally possible. Just not in one statement.
var foo = {
x: "bar",
y: "baz"
};
var oof = {};
({x: oof.x, y: oof.y} = foo); // {x: "bar", y: "baz"}
(Do note the parenthesis around the statement.)
But keep in mind legibility is more important than code-golfing :).
Source: http://exploringjs.com/es6/ch_destructuring.html#sec_assignment-targets
You can just use restructuring for that like this:
const foo = {x:"a", y:"b"};
const {...oof} = foo; // {x:"a", y:"b"}
Or merge both objects if oof has values:
const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
You can return the destructured object in an arrow function, and use Object.assign() to assign it to a variable.
const foo = {
x: "bar",
y: "baz"
}
const oof = Object.assign({}, () => ({ x, y } = foo));
You can destruct an object assigning directly to another object attribute.
Working example:
let user = {};
[user.name, user.username] = "Stack Overflow".split(' ');
document.write(`
1st attr: ${user.name} <br />
2nd attr: ${user.username}`);
You can work with destructing using variables with the same name of object attribute you want to catch, this way you don't need to do:
let user = { name: 'Mike' }
let { name: name } = user;
Use this way:
let user = { name: 'Mike' }
let { name } = user;
The same way you can set new values to object structures if they have the same attribute name.
Look this working example:
// The object to be destructed
let options = {
title: "Menu",
width: 100,
height: 200
};
// Destructing
let {width: w, height: h, title} = options;
// Feedback
document.write(title + "<br />"); // Menu
document.write(w + "<br />"); // 100
document.write(h); // 200
Try
var a = {a1:1, a2: 2, a3: 3};
var b = {b1:1, b2: 2, b3: 3};
const newVar = (() => ({a1, a2, b1, b2})).bind({...a, ...b});
const val = newVar();
console.log({...val});
// print: Object { a1: 1, a2: 2, b1: 1, b2: 2 }
or
console.log({...(() => ({a1, a2, b1, b2})).bind({...a, ...b})()});
I came up with this method:
exports.pick = function pick(src, props, dest={}) {
return Object.keys(props).reduce((d,p) => {
if(typeof props[p] === 'string') {
d[props[p]] = src[p];
} else if(props[p]) {
d[p] = src[p];
}
return d;
},dest);
};
Which you can use like this:
let cbEvents = util.pick(this.props.events, {onFocus:1,onBlur:1,onCheck:'onChange'});
let wrapEvents = util.pick(this.props.events, {onMouseEnter:1,onMouseLeave:1});
i.e., you can pick which properties you want out and put them into a new object. Unlike _.pick you can also rename them at the same time.
If you want to copy the props onto an existing object, just set the dest arg.
This is kind of cheating, but you can do something like this...
const originalObject = {
hello: 'nurse',
meaningOfLife: 42,
your: 'mom',
};
const partialObject = (({ hello, your }) => {
return { hello, your };
})(originalObject);
console.log(partialObject); // ​​​​​{ hello: 'nurse', your: 'mom' }​​​​​
In practice, I think you'd rarely want to use that though. The following is MUCH more clear... but not nearly as fun.
const partialObject = {
hello: originalObject.hello,
your: originalObject.your,
};
Another completely different route, which includes mucking with the prototype (careful now...):
if (!Object.prototype.pluck) {
Object.prototype.pluck = function(...props) {
return props.reduce((destObj, prop) => {
destObj[prop] = this[prop];
return destObj;
}, {});
}
}
const originalObject = {
hello: 'nurse',
meaningOfLife: 42,
your: 'mom',
};
const partialObject2 = originalObject.pluck('hello', 'your');
console.log(partialObject2); // { hello: 'nurse', your: 'mom' }
This is the most readable and shortest solution I could come up with:
let props = {
isValidDate: 'yes',
badProp: 'no!',
};
let { isValidDate } = props;
let newProps = { isValidDate };
console.log(newProps);
It will output { isValidDate: 'yes' }
It would be nice to some day be able to say something like let newProps = ({ isValidDate } = props) but unfortunately it is not something ES6 supports.
You can use JSON class methods to achieve it as follows
const foo = {
x: "bar",
y: "baz"
};
const oof = JSON.parse(JSON.stringify(foo, ['x','y']));
// output -> {x: "bar", y: "baz"}
Pass properties that need to be added to the resulting object as second argument to stringify function in an array format.
MDN Doc for JSON.stringify
This works in chrome 53.0.2785.89
let foo = {
x: "bar",
y: "baz"
};
let oof = {x, y} = foo;
console.log(`oof: ${JSON.stringify(oof)}`);
//prints oof: { "x": "bar", "y": "baz"}
It's not a beautiful way, nor I recommend it, but it's possible this way, just for knowledge.
const myObject = {
name: 'foo',
surname: 'bar',
year: 2018
};
const newObject = ['name', 'surname'].reduce(
(prev, curr) => (prev[curr] = myObject[curr], prev),
{},
);
console.log(JSON.stringify(newObject)); // {"name":"foo","surname":"bar"}

Destruct object with dynamic parameters

I'm trying to destruct object by passing params, but i can't achieve it the way i want. Param's are string's.
function(param){
const obj = {
foo: 'foo',
bar: 'bar'
}
const {[param], ...destructedObj} = obj; // where param === 'foo' || 'bar'
return obj;
}
You can use Object.keys to retrieve keys and then decide which key to use to selectively destruct the object at hand:
const obj = {
foo: 1,
bar: 2
};
const keys = Object.keys(obj);
const { [keys[0]]: x } = obj;
console.log(`${keys[0]}:${x}`);
But I'm not sure where you are going with this?

Destructuring objects as function parameters deep extend

Is it possible to "deep extend" objects when using destructuring to set default properties of an object passed into a function?
Example:
function foo({
foo = 'foo',
bar = 'bar',
baz = {
propA: 'propA',
propB: 'propB'
}
} = {}) {
console.log(foo);
console.log(bar);
console.log(baz);
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
This outputs: (baz is overwrote)
changed
bar
{
"propA": "changed"
}
Is there syntax which will extend the baz object, to give output:
changed
bar
{
"propA": "changed",
"propB": "propB"
}
There is no native-way to do what you ask, but you can write your own function decorator, of course it is a verbose approach...
Note: In order to perform a deep merge you should use some of the existing solution developed by the community, both Object.assign and Object Spread Operator perform a shallow copy of the source, even, writing your own deepmerge function could be error-prone. I suggest you to use lodash#merge that is commonly accepted as one of the solid solutions to the problem.
var {
// https://lodash.com/docs/#merge
merge
} = require('lodash');
function defaultsArgDecorator(defaults, target) {
return function(args) {
return target(
merge(Object.create(defaults), args)
)
}
}
function _foo(args) { console.log({args}); }
var foo = defaultsArgDecorator({
foo: 'foo',
bar: 'bar',
baz: {
propA: 'propA',
propB: 'propB'
}
}, _foo);
foo({bar: "ciao bello", baz: {propA: "HELLO"}})
Since parameters destructuring allow you to use previous parameters in the defaults of other parameters, you can create a property that doesn't exit on the original parameters, for example __baz, and set its defaults using baz.
In the method you'll use __baz instead of baz.
Note: this is a hack, and if the object contains a property by the
name of __baz it will override the default, with unexpected results.
However, you can name the default property with something like
dontUse__baz, which has a very low chance of being used.
Default properties using Object#assign:
function foo({
foo = 'foo',
bar = 'bar',
baz,
__baz = Object.assign({
"propA": "changed",
"propB": "propB"
}, baz)
} = {}) {
console.log(foo);
console.log(bar);
console.log(__baz);
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
Default properties using object spread (requires babel plugin - see link):
function foo({
foo = 'foo',
bar = 'bar',
baz,
__baz = {
"propA": "changed",
"propB": "propB",
...baz
}
} = {}) {
console.log(foo);
console.log(bar);
console.log(__baz);
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
You can also do nested destructuring. You destructure baz, but also destructure propA and propB.
If you need your object whole and don't want to 'rebuild' it, this isn't for you, but it does accomplish one objective of setting default values for unspecified properties nested in an object.
I've left baz as a separate descructured value in addition to it's properties as an example of a sometimes handy pattern, but you would most likely want to remove it since it suffers from the same problem of losing default properties.
function foo({
foo = 'foo',
bar = 'bar',
baz, // likely extraneous and confusing, here for example
baz: { propA = 'propA', propB = 'propB' }
} = {}) {
console.log(foo);
console.log(bar);
console.log(propA, propB);
console.log(baz);
console.log(Object.assign(baz, {propA, propB}));
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
Yep, totally possible!
Solution 1:
function foo({
foo = 'foo',
bar = 'bar',
baz: {
propA = 'propA',
propB = 'propB'
} = {}
}) {
console.log(foo)
console.log(bar)
console.log({propA, propB}) // Because `bar` is renamed to `{propA, propB}`. Hence, no local variable named `baz`
}
Solution 2 (Workaround):
function foo({
foo = 'foo',
bar = 'bar',
baz = {}
}) {
// ...
const baz2 = Object.assign({}, {propA: 'propA', propB: 'propB'} = {})
console.log(baz2) // Yeah, not really a solution
}
You can even do this:
const func = ([{foo, bar: {a, b: BB, c: CC = 'c'} = {}} = {}], ...{0: rest0 = 0, 1: rest1 = '1'}) => { /* do stuffs */ }
The code above is a complicated example, I'll use simpler examples to explain:
Example 1:
const f1 = ({x: varx}) => console.log(varx)
When you call f1(obj), obj.x will be assigned to varx in f1's scope
Example 2:
const f2 = ({xy: {x, y}}) => console.log({x, y})
Similar to f1 but with {x, y} in place of varx, obj.xy will be assigned to {x, y}, so x = obj.xy.x and y = obj.xy.y
Example 3: Now let add create default parameters
const f3 = ({xy: {x, y} = {}}) => { /* do stuffs */ }
Now, you still have to pass obj as an object but you no longer have to provide obj.xy. If obj.xy is undefined, x and y are undefineds
Example 4: Now, let x and y have default values
const f4 = ({xy: {x = 'XXX', y = 'YYY'} = {}}) => { /* do stuffs */ }
If obj.xy you passed is undefined, {x, y} will be set to {x: undefined, y: undefined}, but since x and y also have default values, x will be 'XXX' and y will be 'YYY'
Example 4: "THE ULTIMATE LIFE FORM"
const f5 = ({xy: {x = 'XXX', y = 'YYY'} = {}} = {}) => { /* do stuffs */ }
Guess I don't have to explain this anymore :D

Is it possible to destructure instance/member variables in a JavaScript constructor?

Is it possible to use destructuring assignment in a JavaScript class' constructor to assign the instance variables similar to how you can do it to normal variables?
The following example works:
var options = {one: 1, two: 2};
var {one, two} = options;
console.log(one) //=> 1
console.log(two) //=> 2
But I cannot get something like the following to work:
class Foo {
constructor(options) {
{this.one, this.two} = options;
// This doesn't parse correctly and wrapping in parentheses doesn't help
}
}
var foo = new Foo({one: 1, two: 2});
console.log(foo.one) //=> I want this to output 1
console.log(foo.two) //=> I want this to output 2
There are multiple ways of doing this. The first one uses destructuring only and assigns the properties of options to properties on this:
class Foo {
constructor(options) {
({one: this.one, two: this.two} = options);
// Do something else with the other options here
}
}
The extra parentheses are needed, otherwise the JS engine might mistake the { ... } for an object literal or a block statement.
The second one uses Object.assign and destructuring:
class Foo {
constructor(options) {
const {one, two} = options;
Object.assign(this, {one, two});
// Do something else with the other options here
}
}
If you want to apply all your options to the instance, you could use Object.assign without destructuring:
class Foo {
constructor(options) {
Object.assign(this, options);
}
}
In addition to Nils´s answer. It also works with object spread (...)
class Foo {
constructor(options = {}) {
({
one: this.one,
two: this.two,
...this.rest
} = options);
}
}
let foo = new Foo({one: 1,two: 2,three: 3,four: 4});
console.log(foo.one); // 1
console.log(foo.two); // 2
console.log(foo.rest); // {three: 3, four: 4}
... and/or custom settters for further processing
class Foo {
constructor(options = {}) {
({
one: this.one,
two: this.two,
...this.rest
} = options);
}
set rest(options = {}) {
({
three: this.three,
...this.more
} = options);
}
}
let foo = new Foo({one: 1,two: 2,three: 3,four: 4});
console.log(foo.one); // 1
console.log(foo.two); // 2
console.log(foo.three); // 3
console.log(foo.more); // {four: 4}

Categories