Object Initializer Constant Properties

Does a proposal exist featuring constant properties at object initialization?

Something like:

const a = {
  * "myPropName": "I am a constant",
  * [ "my" + "other" + "prop" ]: "I am also a constant",
}

(I used a star, but I would prefer something more sensible.) Equivalent to

const a = {};
const constant = { writable:false, configurable:false, enumerable: true };
Object.defineProperty( a, "myPropName", { value: "I am a constant", ...constant } );
Object.defineProperty( a, "my" + "other" + "prop", { value: "I am also a constant", ...constant } );

I use object initialization to build name spaces for API modules, and there's a lot of Object.defineProperty involved just to be safe.
I was hoping this was already on track after const appeared, but I haven't found it anywhere.

2 Likes

Do you know about Object.freeze()? Which will effectively make it so you can't reassign to any properties.

One option for syntax would be something like this:

const a = {
  const "myPropName": "I am a constant",
  const [ "my" + "other" + "prop" ]: "I am also a constant",
}

const fits will here, since we're just indicating that we do not with that property to be re-assigned.

This seems like an interesting idea overall. As far as I know, there isn't any proposal like this.

4 Likes

I've used Object.freeze() in a few cases, but I've found it very frustrating. (No configurable properties, lots of getters / setters = unclear behaviors + boilerplate, bug-prone namespace nesting, have to re-call every time you create a copy, somehow track which parts of what are supposed to stay frozen, etc. )

I considered something like a = { myConstProp :: {} }, but I prefer that const syntax.
Clarity over brevity here. The immutability should stand out.

I'm not qualified to have much to do with a proposal. But I could help if someone more experienced is interested.
I'm not sure about its details. Would immutability survive destructuring?
b = { ...a }; //does b have some immutable properties? (my guess: no)
Can array literal entries be immutable?
c = [ const id, 'a', 'b', 'c' ] (guess: no)

There's potential for decorators to (eventually) facilitate this.

Ah, yes, didn't think about decorators, that would make for a great solution to this problem. Decorators would also provide a clean way to set other property descriptors, like enumerability.

As for your questions @0X-JonMichaelGalindo - if we did have dedicated syntax, it would probably just be a shorthand for the writable property descriptor, so it'll behave exactly the same as your initial verbose example does. This means it would not survive destructuring, and it also means it's theoretically possible to make array properties non-writable (that's a weird concept - I feel like that would break a number of array functions) - I doubt there would be a reason to add syntax support for it, but if we piggy back off of decorators, then we might get that support, weather we like it or not. (After all, array elements are just numeric properties on the object).

Right! Thanks. Decorator meta-magic... Is there anything they can't do (*eventually)?
Definitely preferable to the limited case.

a = { @static prop: "I will never change" }

Back to waiting, then. :hourglass_flowing_sand:

Since you asked... Decorators were on the agenda for the TC39 meeting this week and this slide mentions what Decorators, in there current form, can and can not do.

They cannot :

  • Replace with a different type of value
  • Add, remove, or replace values other than the decorated value
2 Likes

There is also GitHub - tc39/proposal-record-tuple: ECMAScript proposal for the Record and Tuple value types. | Stage 2: it will change!

For creating immutable Records. The current proposal is like this:

const record = #{
  myPropName: "I am a constant"
};

Object.getOwnPropertyDescriptor(
  record,
  "myPropName"
); // { configurable: false, writable: false, value: "I am a constant" }

const secondRecord = #{
  ...record,
  aNewProp: 2 
};
3 Likes

I very much approve of those artificial limitations on decorators! The (dangerously invisible) magic will be less prone to "leak" out of the line it's used. Fully compatible with my use cases.

I can't think of a specific use for immutable records at the moment. I foresee issues similar to freeze(). Still, I always want more tools to work with. I've found uses for everything else so far.

2 Likes

Hi @0X-JonMichaelGalindo,

I love the concept. I would prefer to have readonly instead of const. Because const is usually used with variable declarations and not properties.

const a = {
  readonly "myPropName": "I am a constant",
  readonly [ "my" + "other" + "prop" ]: "I am also a constant",
}

Unlike Object.freeze() this sets certain properties as readonly and not all.

If we do get a syntax like that we could take it to class level. (This is just like in Typescript)

class Person {
  readonly name = "Ethan";
}

This could also save us from the boilerplate issue in OOP.

class Person {
  readonly name;

  constructor(name) {
    this.name = name;
  }
}

// is the same as...

class Person {
  constructor(readonly name) {}
}

Thank you :grinning:.

1 Like

Yep, both good.
Decorators will let you do whichever works best for your case. I prefer the decorators to the specific syntax because of how flexible they are.
(It's the upcoming feature I'm most looking forward to!)
Although, they're coming to classes first from what I understand, so it'll be a while before I can use them the way I want.

const A = ({ @static id: UUID() });
const a = A();
class A {
    @readonly id
    constructor() {
        this.id = UUID();
    }
}
const a = new A();
2 Likes