Instantiating a 3rd-party class by name in ES6 - javascript

How can I instantiate a class if all I know is its name, given the following restrictions?
ES6
The class is defined by a third-party. I have no way of knowing about the class ahead of time.
All of the answers I've seen on Stackoverflow assume that I define the class being instantiated, and as such I can create a mapping between class names and their constructions ahead of time. Example: https://stackoverflow.com/a/31790015/14731
Seeing as this cannot be done for 3rd-party classes, what can I do?
Is eval() the only way?
What I am trying to do
Users are expected to pass in a class name and I am supposed to instantiate the class, assuming the existence of a constructor that takes exactly one String argument. More specifically, I am allowing users to override the type of exception my library will throw on error.

What worked for me:
Instead of having users pass in the name of the exception they wanted to instantiate, I just had them pass in the exception constructor.

Related

Design pattern to choose different database

I have created a class to interact with my database:
class MyDatabase {
connect() { /* ... */ }
}
And the database has two types of modes: admin and client. I would like to have different classes for each mode:
class MyDatabaseAdmin {}
class MyDatabaseClient {}
Both of them will implement the same interface, but with different underline implementations. I would like to know if there is a design pattern to instantiate the parent MyDatabase choosing one over the other. Something like:
const db = new MyDatabase({ mode: 'admin' })
db.connect() // parent calls MyDatabaseAdmin.connect
I don't need a perfect answer, just some direction to what I should search for.
Thanks.
If they have no code in common, then they are really just two separate classes. You probably don't even want the admin code to be present in the browser since it can't be used there anyway.
You could have a single factory function that looks at an admin parameter and instantiates the appropriate database object and returns it, but I don't think I even see why you'd bother with that.
Just have each client instantiate the appropriate DB object. If there's any common code, you can have both implementations inherit from a common base and put the common code in the base class.
Right! I forgot to mention, but there are some common code... the connection and authentication is exactly the same, for example. Do you happen to know any design pattern that would perfect fit for this use case? Should I research about Factories?
I think a common base class with inheritance solves the problem here. It gives you a natural place to put the common code without having to include server-side code in the client implementation. The browser implementation and the server implementation would each be a subclass that are present only on their respective platforms. The common base class would be present and used in both places.
You just have the client instantiate the appropriate leaf class and the shared code lives in the base class. If you want to hide the actual class constructors, you can use a factory function (it's just a simple function that looks at conditions and makes an appropriate object for you and returns it), but I'm not sure there's any compelling reason to use a factory function here. You would only include the appropriate leaf class on the platform for which it is intended so there's no place where you might use one or the other in the same code.
would you consider having only 'users'? then each user could have a 'role' that would be either 'user' or 'admin'. So based on that 'role' you will define the privileges for each user. I find this solution easier for this kind of stuff but let me know if it does not match your case.

Get available properties of interface without initializing

I'm trying to create a generic "mapping" method that can take an interface and JSON response then map the available keys to the interface. The issue I'm having is there seems no way to get the available properties of an interface without initializing them.
Is there a way to get the value of an interface without having to define it?
Interfaces and other type information (with exceptions) are not available at runtime.
However, you can define a method that deserializes a JSON string into a given type. const myThing: IThing = JSON.parse(myJsonString); will cast it to the type IThing.
If you have a class Thing that implements IThing, you can use Object.keys to iterate over the keys of an instantiated Thing, and match the key indices together, like thing[key] = JSON.parse(...)[key]
interface and types in typescript are only checked when compiling (from ts to js). So, at runtime (which runs js), there is no information about interface.
But you can implement this with use of class and reflect-metadata and decorators, like class-transformer do.
Simply switching my interfaces to a class was the solution. I am then able to create a blank instance and list out all available properties.

Why should I use interfaces as data types in angular if there are classes allready?

I recently watched tutorial of my teacher, and he show us this code:
And he also said products array which is type of any [] IS NOT USING BENEFITS OF STRONGLY TYPE which is feature of TypeScript so it should be defined as INTERFACE, but I'm wondering now, why he did not create a class and that products array might be of that class type??
He said Interfaces purpose is to provide strongly typing and tooling support..
So he wrote this interface:
So I'm wondering why he did not create a class like :
export class Product .. and later he would use products : Product [] ..
So basically I can not figure out why is Interface as dataType better here instead of class?
Sorry for screenshots and not real code, that's because he hosted online video lessons..
Thanks
Check this text writen by James Henry maybe that will clarify you this issue. In short: Unlike classes, interfaces are completely removed during compilation and so they will not add any unnecessary bloat to our final JavaScript code.
Think of interfaces as a blueprint for your object — a brief set of instructions that guarantees that a certain set of fields / methods will be available on objects tagged with that interface. They provide you with a means of taking advantage of strong typing while keeping your code as lightweight as possible. As mentioned, the interface is removed and compile time because it doesn’t actually have any programmatic implications — it’s strictly to make the code less error-prone and easier to work with for you and whoever else.
If you need to specify implementation details, such as getter / setter / constructor logic or methods, that’s when you would use a class. In fact, if the logic for the calculateDiscount() method in your example is expected to remain the same across all Products, it’s possible that a class could make more sense in this case.
Classes can work as interfaces in TypeScript. Interfaces cannot work as classes. One of them can be chosen based on the principle of parsimony.
Things like
class SomeProductClass implements ProductClass {...}
and
const plainProduct: ProductClass = {...};
happen often.
However, when a class is defined, it's expected that it or its descendant will be instantiated. If it won't, this would be misleading, because this is what interfaces are for.
It's common in Angular to define abstract class that won't be instantiated, but that's because abstract classes can be used as both interfaces and dependency injection tokens.

Should react class methods be pure?

I'm wondering should I use 'this.props' and 'this.state' inside React class methods or prepare only needed data from state and props outside and pass it to a method as parameters?
First option looks quicker, but maybe more error prone.
Personally I'd treat the component methods quite the same as usual methods in javascript. For me it means that just by looking at the method header I can at least suppose, base on the name and entry params, what the specific method is responsible for.
Second thing is, that it can depend on component shape itself.
Lets imagine that in your component you got the method named 'markPersonAsAbsent'.
If your component just handle single person than in fact can be quite obvious that we should operate on something like this.props.person.
But if your component is more like a list of people which can be inline edited, not just the info card of a single person, than for sure we'd expect to pass a specific person as param to that method.
In that scenario of course we can argue that the components are wrongly designed and should be more atomized, but just wanted to describe simple example.
So personally I just try to focus how to make my components readable and let's say 'predictable'.
It is not error prone, since this.state and this.props are read only properties, so you can't change their values directly.

What is the reason ES6 class constructors can't be called as normal functions?

ES6 class constructors can't be called as normal functions. According to ES6 a TypeError should be raised when this is done. I used to think that classes were just syntactic sugar for a constructor function + functions in the prototype, but this makes it slightly not so.
I'm wondering, what was the rationale behind this? Unless I missed something, it prevents calling the function with a custom this, which could be desirable for some patterns.
A revisit to the ES6 spec shows how calling a Class function object without new is disabled by combining sections 9.2.9 and 9.2.1:
9.2.9 MakClassConstructor (F)
...
3. Set F’s [[FunctionKind]] internal slot to "classConstructor".
and when specifying the [[call]] method as opposed to the [[contruct]] method of a function:
(9.2.1) 2. If F’s [[FunctionKind]] internal slot is "classConstructor", throw a TypeError exception.
No restrictions are placed on calling function in section "11.2.3 "Function calls" of ES5.1.
So you are not missing anything: you can't use apply on a class constructor function.
The major rationale is probably both to make class extensions a fairly rigorous exercise, and to detect some early forms of error. For example you can't call Promise except as a constructor - and leaving out new before a call to Promise is a programming error. In regards extending classes, note that the constructor property of class instances is correctly set (the last class after possibly multiple extensions) and the the .prototype property of the class constructor is read only - you can't dynamically change the prototype object used to construct class instances, even though you could change the prototype property of a constructor function.
I used to think classes were syntactic sugar but have moved away from the concept.
To recap, your two main points are
ES6 class constructors can't be called as normal functions.
It prevents calling the function with a custom this
The first thing to note is that from the standpoint of the runtime behavior of a class, those are to points are not functionally tied together. You could for instance allow Foo() without new but still have Foo.call({}) behave like it had been newed. The ability to call as a function can allow setting this, but it doesn't have to, the same way Foo.bind({})() would bind a this and then call the function, but the bound this would be ignored.
For the rationale behind the decision, I can't give you a primary source, but I can tell you there is one solid reason. ES6 class syntax is "syntax sugar", but not for the simplified code you likely have in your head. Take for example this snippet, given your goal.
class Parent {}
class Child extends Parent {
constructor() {
// What is "this" here?
super();
}
}
Child.call({});
What should this do? In ES6, super() is what actually sets this. If you try to access this before having called super(), it will throw an exception. Your example code could work with Base.call({}) since it has no parent constructor, so this is initialized up front, but as soon as you're calling a child class, this doesn't even have a value up front. If you use .call there is no where to put that value.
So then the next question is, why do child classes not get this before super()? This is because it allows ES6 class syntax to extend builtin types like Array and Error and Map and any other builtin constructor type. In standard ES5 this was impossible, though with the non-standard __proto__ in ES5 it could be simulated roughly. Even with __proto__ it is generally a performance issue to extend builtin types. By including this behavior in ES6 classes, JS engines can optimize the code so that extending builtin types works without a performance hit.
So for your questions, yes, they could allow Foo.call(), or Foo(), but it would have to ignore this either way in order to allow for extending builtin types.
what was the rationale behind this?
It's a safeguard. When you called an ES5 function constructor without new, it did very undesirable things, failing silently. Throwing an exception helps you to notice the mistake.
Of course they could have opted for the call syntax to just work the same as construction, but enforcing the new keyword is a good thing that helps us to easily recognise instantiations.
It prevents calling the function with a custom this, which could be desirable for some patterns.
Yes, this is what fundamentally changed in ES6. The this value is initialised by the superclass, which allows subclass builtins with internal slots - see here for details. This conflicts with passing a custom this argument, and for consistency one must never allow that.

Categories