Class syntax with parametrized class name - javascript

I want create classes dynamicaly in runtime, and I want parametrize the class name.
function newClass(className:string) {
return class MyDynamicClass { }
}
// expected class name: "Person"
let personClass = newClass("Person")
// expected class name: "Contact"
let contactClass = newClass("Contact")
P.S.: The proposed duplicate question (ES6 Dynamic class names) is with wrong accepted answer and other answers does not fulfil my requirements.

I don't think it is possible to make dynamic class name like here:
class [className] {}
It is not allowed.
However, you can create an object with className property (class expression):
const newClass = (className: string) => ({
[className]: class { }
}[className])
// expected class name: "Person"
let personClass = newClass("Person")
personClass.name // Person
I know, personClass returns class {} without name. I think this is the closest working solution.

Related

How to create fields in a class using Symbol

I have class Movie. Movie constructor should provide a generation of unique product id within the application no matter how many products are created. You also need to define a field with the name of the movie. But according to the condition, for this I have to use Symbol data type. How can i do this?
class Movie {
constructor(name) {
//here I need to generate a unique id;
//here I need to define name fields
}
}
class Movie {
sym = Symbol('symbol description')
constructor(name) {
this.symInConstructor = Symbol('symbol description')
// this.sym != this.symInConstructor
// M1.sym == M2.sym <=> M1 == M2
}
}
// remeber, Symbol() != Symbol(), each call creates a unique one
However note that you can't ever serialize a Symbol.
If you need a serializable thingy, generate uuid or whatever
Also it may have sense to not use Symbol, but to use the class instance itself, I don't see how the Symbol may be used
Create a global constant, and use square brackets access
const MovieName = Symbol('a key for MovieName')
class Movie {
[MovieName] = "The Movie";
["myString"] = "is equivalent to:"
// myString = "is equivalent to:"
// and must be used for Symbols as
constructor() {
this[MovieName] = "The Movie in constructor"
}
// may keep is somewhere like this for usage in other places
static movieNameSymbol = MovieName
}

In JS can you inherit methods from your class and properties from an instance of your parent class?

In building an order tracking software, I want an inheritance structure that looks something like this
Default SKU Propreties
|
----------...
|
SKU 001
|
--------...
|
Item AAA
I want the Item objects to inherit properties and methods from their parent SKU objects, but also have methods specific to Item objects.
I have tried something like Class Item extends SKU, but of course this just makes the SKU class the Item instance's ancestor, and not the SKU instance which has the relevant properties. I know you can do something like itemInstance = Object.create(skuInstance) to inherit from a SKU instance object, but then itemInstance does not get any methods defined on the Item class.
Thank you for your help :)
Edit, additional info:
I want a SKU instance to have some properties and methods like:
SKU 001
Name: 'Custom T-Shirt'
getLaborCost()
I want each Item instance to inherit the values that are common to all Items under that SKU. I want it also to have properties like proofs that can be unique to each Item instance.
Right now I am achieving this by having "item" object instances have SKU instances as their prototypes. The prototype ancestry looks like this:
SKU Class (with methods)
v
SKU instance (with properties)
v
"item" instance (with properties)
However, this means I can't have items be actual instances of an Item class and get unique methods like attachProof(), which I would not want to be available on the SKU instance object.
from my comment to MikeM:
"I want the user during program execution to be able to change the skuInstance.name and all of its items have their itemInstance.name resolve to the current value. I also want the user to be able to override some item instance properties which would otherwise be inherited."
Here is an example of how you may be able to meet your requirements without using inheritance.
Note that by properties I mean methods also, as methods are properties whose value is a function.
See MDN for some cautions related to the use of Object.assign.
class Item {
#sku;
constructor(props) {
const { sku, ...others } = props;
Object.assign(this, others);
this.#sku = sku;
}
get name() { return this.#sku?.name }
set name(val) { /* disallow */ }
// Add further properties of all Item instances...
}
class SKU {
#itemProps;
constructor(props) {
const { itemProps, ...others } = props;
Object.assign(this, others);
this.#itemProps = itemProps;
}
item(props) {
return new Item({ ...this.#itemProps, ...props, sku: this });
}
// Add further properties of all SKU instances...
}
let sku1 = new SKU({ name: 'Custom T-Shirt', itemProps: { color: 'red' } });
let item1 = sku1.item({ size: 'L' });
console.log(item1.name); // "Custom T-Shirt"
sku1.name = 'Slogan T-Shirt';
console.log(item1.name); // "Slogan T-Shirt"
console.log(item1.color); // "red"
console.log(item1.size); // "L"

How can I stop JavaScript from passing a class by reference?

I have the following code in the constructor of a class (shortened for the purpose of the question):
constructor(effect: EffectInstance, names: string[], count?: number) {
this.effect = effect; // instance of a class "Effect"
let name; for (name of names) {
this.custom.set(name, this.effect); // custom: Map
}
}
EffectInstance is the type of this class, which is generic
When I change this.effect.name in a method of the class, or when I grab the effect from the Map this.custom and change its name, both are changed.
From what I can tell, this is due to JavaScript's pass-by-reference behavior with objects, as I'm 100% certain that I'm not modifying the values I don't want modified. (I'd like to be able to rename the Effect instance in the custom Map, but keep this.effect.name unchanged)
I tried to re-instantiate the classes with the parameters in constructor(), but this raises a new issue: I'd be losing types, and I can't seem to figure out how to work around this. Here's what I tried:
(EffectInstance, for reference: <EffectInstance extends Effect>)
constructor(effect: EffectInstance, names: string[], count?: number) {
this.effect = effect;
let altEffect = effect instanceof PlayerEffect ? new PlayerEffect(effect.name, effect.ignoreRaces) : new Effect(effect.name);
let name; for (name of names) {
this.custom.set(name, altEffect);
}
}
Doing so, TS raises this error on altEffect:
TS2345: Argument of type 'Effect' is not assignable to parameter of type 'EffectInstance'.   'Effect' is assignable to the constraint of type 'EffectInstance', but 'EffectInstance' could be instantiated with a different subtype of constraint 'Effect'.
I need to either stop the pass-by-reference behavior or preserve the type that EffectInstance contains. How can I do this?
Most languages pass objects by reference, so this is not a unique behavior with javascript.
If you want to pass a copy of the class instance and not the original instance and send the clone where you don't want send the original instance.
class Car {
constructor(name) {
this.name = name;
}
}
let orignalClass = new Car('BMW');
let cloneClass = Object.assign(Object.create(Object.getPrototypeOf(orignalClass)), orignalClass)
console.log(orignalClass);
console.log(cloneClass);
// now both can be updated individually
orignalClass.name = 'BMw-1';
cloneClass.name = "BMW-copy"
console.log("after update");
console.log(orignalClass);
console.log(cloneClass);
through your code, this.custom type should be Effect.
constructor(effect: EffectInstance, names: string[], count?: number) {
this.custom = new Map<string, Effect>(); // altEffect type could be PlayerEffect or Effect
this.effect = effect;
let altEffect = effect instanceof PlayerEffect ? new PlayerEffect(effect.name, effect.ignoreRaces) : new Effect(effect.name);
let name; for (name of names) {
this.custom.set(name, altEffect);
}
}

Java Script: Setting Value to the Object by id, where id is last letter of Object

As for the heading: it seems a little bit confusing but it is not.
In React I'm doing re-usability of code
I have
state={
colorObj1: {r:'0',g:'0',b:'0',a:'1'},
colorObj2: {r:'0',g:'0',b:'0',a:'0'},
colorObj3: {r:'0',g:'0',b:'0',a:'1'},
colorObj4: {r:'0',g:'0',b:'0',a:'0'},
colorObj5: {r:'0',g:'0',b:'0',a:'1'}
}
I want this function --> By Id of Object, I want to set the color to a particular Object.
id value --> 1,2,3,4,5
getSelectedColor=(color,id) => {
this.setState({colorObj{`id`}: color}) //WRONG CODE
}
You should use Computed property names as follow:
this.setState({[`colorObj${id}`]: color})
It's not a react issue. You want to connect string with dynamic variable. You can use: 'someBasicStr'+dynamicVar or with template string(es6+): someBasicStr${dynamicVar}, any variable will be inside ${}.
try
class MyClass {
constructor() {
this.state={
colorObj1: {r:'0',g:'0',b:'0',a:'1'},
colorObj2: {r:'0',g:'0',b:'0',a:'0'},
colorObj3: {r:'0',g:'0',b:'0',a:'1'},
colorObj4: {r:'0',g:'0',b:'0',a:'0'},
colorObj5: {r:'0',g:'0',b:'0',a:'1'}
}
}
setSelectedColor(color,id) {
this.state['colorObj'+id]=color;
}
getSelectedColor(id) {
return this.state['colorObj'+id];
}
}
// TEST
let c = new MyClass();
c.setSelectedColor({r:'1',g:'1',b:'1',a:'1'},6)
console.log(c.getSelectedColor(6));
console.log(c.getSelectedColor(2));

Typescript: Create interface based on a class

I got a class called MyClass. It has a bunch of properties.
I want to create an interface that contains the options of that class. Many options have the same name and typing than MyClass, but not all.
Edit: Most options properties are optional.
The goal is to duplicate the least possible.
Right now, I'm using a dummy object to avoid code duplication. Is there a cleaner solution than this?
class MyClass {
callback:(p0:number,p1:string,p2:string[]) => number[];
myAttr:number;
composed:string;
constructor(options:MyClassOptions){
if(options.callback !== undefined)
this.callback = options.callback;
if(options.myAttr !== undefined)
this.myAttr = options.myAttr;
if(options.composedP1 !== undefined && options.composedP2 !== undefined)
this.composed = options.composedP1 + options.composedP2;
}
}
var dummy = <MyClass>null;
interface MyClassOptions {
callback?:typeof dummy.callback;
myAttr?:typeof dummy.myAttr;
composedP1:string;
composedP2:string;
}
Many options have the same name and typing than MyClass, but not all.
If this is the case, there's not a good option.
If you want to have exactly the same members, and your class doesn't have any private or protected properties/methods, you can write
interface MyClassOptions extends MyClass {
extraProp: string;
}
One thing you could do is make a base class with just the options you want to share, make the interface from there with the "real" class you use being a derivative of the base class.

Categories