Difference between class and function blocks in React? - javascript

I was going through an article on Commonly faced problems with React and there i found this example.
class Numbers extends React.Component {
const arrayOfNumbers = _.range(1, 10);
// ...
}
It said "The code above is invalid because inside the body of a JavaScript class you don’t have the freedom of doing just about anything. You can only define methods and properties using limited syntax.
This is a bit confusing because the {} used in the class syntax looks like the plain-old block scope, but it’s not.
Inside a function-based component, you DO have the freedom of doing just about anything"
// Totally Okay:
const Number = (props) => {
const arrayOfNumbers = _.range(1, 10);
// ...
};
Can anyone explain to me why the above statement inside the class body is invalid ?? And what is that strange looking _. symbol ??

Can anyone explain to me why the above statement inside the class body is invalid ??
That's just the way the syntax for classes is. You can define functions in the body of the class, and they'll go on the prototype. If you want any instance variables, you do those in the constructor.
And what is that strange looking _. symbol ??
It's a variable named _. In this case, it's almost certainly a reference to the Lodash library, a commonly used library with utility functions.

Related

is there a way to import all keys inside a package with require?

I would like to know if there is a way to import all elements of a package/file without directly naming them
example:
//file1 - things.js
module.exports = {
thing1:{...},
thing2:{...},
thing3:{...}
}
//file2 runner.js
const things = require("./things")
console.log(things.thing1)
//in this case it imports the things.js and its elements and assigns the variable things,
//but that's not what I want
//I want it to import the native variables from the things.js file without having to pull each one individually
//---
//i know i can import the native variables by pulling them like this:
const { thing1, thing2 } = require("./things")
console.log(thing1, thing2)
//but this is not what I want either, what I want should look like the following example:
const {} = require("./things")
console.log(thing1, thing2, thing3)
//imporiting all native variables without having to define one by one
Short answer, no.
When using module.exports, you're effectively assigning a value to the return of require. That value can be any valid JavaScript value, in this particular case, an object. Presently, JavaScript does not have a mechanism for destructuring an object into all of its constituent keys, which is functionally what you're asking for.
In fact, JavaScript has no mechanism at all for implicit variable declaration, at least not in strict mode. If it doesn't appear in the source code, it's not there.
A hacky way around this could be something like this:
const thing = require('../thing.js');
for (const key in Object.keys(thing)) {
global[key] = thing[key]; // using "global" here instead of "window" for environment-agnostic code
}
This will force all of your exports to be available in the global scope, accessible as if they were declared. However, your editor/IDE will get very upset that it doesn't know where these variables came from, and this is horrific, unrecommendable practice.

Is there something like Lombok for TypeScript?

I'm looking for a way to reduce the boilerplate code of my NodeJS backend. In Lombok there is e.g. the possibility to inject constructors and getter/setter by annotation for objects.
Is there a way to do this in TypeScript?
I googled it quickly and found projects like this which attempt to bring Lombok-like capabilities to TypeScript, but as you can see, those project are scarce and not that widely used. That implies a question: Why would you want a tool like that?
TS is already pretty good in reducing boilerplate. When I define a class, I usually do it like this:
class A {
constructor(private fieldA: string, private readonly fieldB = 0) {}
}
This is quite concise, isn't it? I guess you are comparing capabilities of TS to those of Java. Java is very wordy and Lombok helps with that greatly. But TS and JS are different, and while some problems, which Lombok solves, are solved by TS already, others are not an issue in the world of TS and JS.
First of all, the syntax above creates class fields of certain types, with access modifiers and you can also spot the readonly keyword in front of fieldB and its default value 0. On top of that, those are created together with a constructor, which implicitly assigns values to instance fields upon execution (see, there is no this.fieldA = fieldA). So this already more than covers the Lombok's capability to inject constructors. Note on this: In JS (and therefore in TS), you can have only single constructor. JS doesn't support method overloading.
Now about the getters/setters, those are not used the same way in JS (or TS) as they are in Java. In JS, it is a norm that you are working with fields directly, and the setters and getters are used only in special cases where you want to:
Forbid setting a value to an object's property in runtime by defining only a getter. Now this is usually a bit of an overkill, and since you use TS, you can just declare the field as readonly and compiler will make sure you don't assign to that property - no need to use a getter. If you develop in JS without compile time checks, the convention is to mark properties that are private (those you definitely shouldn't modify) with underscore. Either way, it can still happen that you modify a variable that you aren't supposed to modify, but unlike in Java, this is not deemed a reason good enough to use get/set everywhere in JS (and TS). Instead, if you really need to be certain that no modifications happen in runtime, you either use the aforementioned getter without setter, or you configure the object's property as non-writable.
Having a custom logic in set/get functions is the other good reason to employ them. A common use case for this is a getter that is computed out of multiple variables but you still want it to look like an field on an object. That's because in JS, when you invoke a getter, you don't actually use () after the getter name. Now because this logic is custom, it can't be generated just by using an annotation.
So as you can see, some problems Lombok deals with in Java are already dealt with in TS and others are non-issues.
Edit 5-9-2021 - answer to #Reijo's question:
Lomboks functionality goes beyond getters/setters/constructors. Looking at the #Builder Annotation, I am interested in what you would say about this.
If the question is just about whether there is a TypeScript/JavaScript library that offers more or less the same collection of utilities as Lombok for Java, to my knowledge the answer is NO. I think partly it is due to capabilities that TypeScript provides out of the box (as I already outlined above), which brings me back to the point that Java needs Lombok more than languages like TypeScript or Groovy do. When you need something that TS doesn't provide, like the builder pattern, you can use libraries solving a particular problem, like builder-pattern (using JS Proxy in its core) or thanks to the flexible nature of JS (and in effect TS) write it on your own easily.
That's all nice, but you'd perhaps like to add functionality in more declarative way - via annotations (in TS world those are called decorators and they work differently), as Lombok does it. This might prove complex.
First of all, if you modify the type via decorator in TS, TS compiler doesn't recognize the change. So if you augment class by, let's say, adding a method to it in your decorator, TS won't recognize that new method. See this discussion for details.
This means that you either give up on decorators and use functions instead to modify the type (which you can), or you dive into AST. That's btw how Lombok works. It takes annotated types in a compilation phase called annotation processing and thanks to a hack in javac (and Eclipse compiler) modifies their AST (to eg. create an inner builder for given class). One could do it in a somewhat similar way with TS/JS.
Though there is nothing like annotations processing in TS nor JS as such, you could still create a build step that takes a source code and modifies it's AST to achieve your goals (which is how Babel works too). This might result in adding a method to a class, generating a builder etc. based on an annotation (in a broad sense - not necessarily a decorator) used.
This approach is a challenge though. Besides AST being an advanced topic, even if you get it working, you'd need support from your IDE, which nowadays also means support from language servers. And that's not for the faint of heart.
However, my edit is not supposed to scare anyone away if you plan to create something like Lombok for TS, since it seems quite some people would like to see it in TS/JS world. It should only show you what lies ahead ;).
I found an alternative to #Getters and #Setters Lombok decorators.
Try this :
import { capitalize } from "lodash";
const Getters = () => <T extends {new(...args:any[]):{}}>(constructor:T) => {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
const props = Reflect.ownKeys(this);
props.forEach((prop: string) => {
const capitalizedKey = capitalize(prop);
const methodName = `get${capitalizedKey}`;
Object.defineProperty(this, methodName, { value: () => this[prop] });
});
}
}
}
const Setters = () => <T extends {new(...args:any[]):{}}>(constructor:T) => {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
const props = Reflect.ownKeys(this);
props.forEach((prop: string) => {
const capitalizedKey = capitalize(prop);
const methodName = `set${capitalizedKey}`;
Object.defineProperty(this, methodName, { value: (newValue: any) => { this[prop] = newValue } });
});
}
}
}
#Getters()
#Setters()
export class Person {
[x: string]: any;
nom: string;
prenom: string;
constructor(nom: string, prenom: string) {
this.nom = nom;
this.prenom = prenom;
}
}

Do we really have to OOPsify everything in TypeScript?

I have joined a new company and here they have created classes for just about everything, even for the unrelated utility functions.
Consider this:
export default class Utils {
static method1()
static method2()
static method3()
}
vs
export const method1 = () => {}
export const method2 = () => {}
export const method3 = () => {}
Is there any specific advantage one gets by encapsulating the independent methods inside a class? Which is the recommended way for a scalable code base?
This is a common misconception about Typescript. Typescript does not mean you have to use classes. Typescript is Javascript with types. Write your code as you would in Javascript, add types where necessary, and you should be fine.
If you want to take advantage of classes (an ES2015 feature not necessarily a Typescript feature) Typescript will help you have strong types for the classes. But you don't need classes to write good Typescript.
The reasons this misconception probably appeared is that the early demos always showed classes as they were still not in most browsers and needed down-compilation and everyone wanted them. This lead people to the false impression that Typescript works best with classes. But this is definitely not so.
In your particular case I would actually argue it is a bad use of classes. Static classes are an invention for languages that do not allow functions to live anywhere else but in a class. In Javascript the module can encapsulate such static methods as well as any class and is a more Javascript oriented way to do things.

Reusing class names in JavaScript

Is it in someway possible to reuse a class name that is defined in the Global objects list found here? (Like Number, String)
Lets say that I want to have my own String class. I can define it, and use it like this:
String.js
export default class String {
}
App.js
import String from './String'
let string = new String();
This actually works, but then
PHPStorm tells me: yeah you used a primitive object wrapper (thinking it's
the global object String).
Then ESLint tells me: Disallow Primitive Wrapper Instances (no-new-wrappers)
And lastly SonarQube tells me: The use of wrapper objects for primitive types is gratuitous, confusing and dangerous. Simple literals should be used instead.
So yeah is there a way to encapsulate my class so it doesn't get confused with the global String class?
import './String'
Function and class definitions are local to the module. You're importing the file, but not using anything from it.
That's why this:
let string = new String();
will use the global String—there is no String definition in the module scope.
Make sure you name the imports you need:
import String from './String'
Incidentally, this is one of multiple reasons why it is better practice to give your String class a unique name, like PhysicsString or StringMaterial or Thread. That way if you forget to import it somewhere, you won't accidentally be using the global definition.

correct way to expose a const in javascript using ES6 classes?

const SOME_CONSTANT = 'test case';
class SomeClass {
static get SOME_CONSTANT(){
return SOME_CONSTANT;
}
}
Consider this pattern. This achieves the following two objectives:
internally, the item cannot be reassigned
externally, the item cannot be reassigned
However, it fails in that it breaks naming conventions for methods - starting with a capital letter is reserved for functions invoked with 'new'. This trips off an IDE warning in Webstorm.
What is the best way around this ?

Categories