Private class variable declaration - javascript

I am trying declare a private class variable for a super class and I seem to have trouble doing so. I there something I am missing? This is my code so far.
class Animal {
constructor(_name) {
this._name = _name;
}
name() {
console.log(`${this._name} is my name.`);
}
}
new Animal('Bob').name();

Private fields start with # but their scope will keep them hidden from subclasses.
class Animal {
#name
constructor(name) {
this.#name = name;
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields

Private class features are available in the following browsers:
Chrome
Edge
FireFox
Opera
Safari
74+
79+
90+
62+
14.1+
Here is an example of your class with a private instance field called name:
class Animal {
#name;
constructor(name) {
this.#name = name;
}
get name() {
return this.#name;
}
toString() {
return `${this.#name} is my name.`;
}
}
const bob = new Animal('Bob');
console.log(bob.name);
console.log(bob.toString());
// console.log(bob.#name); <-- SyntaxError

Related

Javascript Cannot read property 'x' of undefined

I don't understand the error in the code below. I tried calling another class's function from another class. But I gives the error error: Uncaught TypeError: Cannot read property '_name' of undefined
class Person {
constructor() {
this._name = "Name-Person";
}
getName() {
return this._name;
}
}
class Test1 {
constructor() {
let p = new Person();
new Test2(p.getName);
}
}
class Test2 {
constructor(getName) {
console.log(getName());
}
}
new Test1()
How can I fix the error?
When passing the function to Test2 you need to bind p to the function
new Test2(p.getName.bind(p));
class Person {
constructor() {
this._name = "Name-Person";
}
getName() {
return this._name;
}
}
class Test1 {
constructor() {
let p = new Person();
new Test2(p.getName.bind(p));
}
}
class Test2 {
constructor(getName) {
console.log(getName());
}
}
new Test1()
you can use public class field:
class Person {
constructor() {
this._name = "Name-Person";
}
getName = () => {
return this._name;
}
}
class Test1 {
constructor() {
let p = new Person();
new Test2(p.getName);
}
}
class Test2 {
constructor(getName) {
console.log(getName());
}
}
new Test1()
Because you are passing the function and not the entire class or its value, _name does not exist in the context of the Test2 constructor.
A couple of simple solutions is to either pass in the result of getName() to the constructor, or the entire class of Person.
new Test2(p); // And in Test2 use p.getName()
// or
new Test2(p.getName()); // And in Test2 use the result

How to test Typescript class members in React with Jest

I have a Typescript class (with react) with public and private member functions.
export class Myclass {
private itemList: SomeItem[];
constructor(params) {
}
public method1() {
}
private method2() {
}
}
How can I test method1 and method2 in my code using jest. I can do it for functions who are exported and are not members of a class. But how can I do it for class members.
First, you need an instance...
const instance = new MyClass()
Then, you can test method1 by calling it directly...
expect(instance.method1()).toBe(...)
For method2, you've got 3 options...
Use #ts-ignore:
// #ts-ignore
expect(instance.method2()).toBe(...)
Cast as any:
expect((instance as any).method2()).toBe(...)
// no type safety on method2
Change to protected and extend:
class MyClass {
protected method2() {}
}
class MyClassTester extends MyClass {
public runTests() {
expect(this.method2()).toBe(...)
}
// OR
public method2Accessor(...args: any[]) {
return this.method2(...args)
}
}
const instance = new MyClassTester()
instance.runTests()
// OR
expect(instance.method2Accessor()).toBe(...)
// fully type-safe
You have to create an instance of the class and then call its public methods in your test. There is no way around it.

TypeScript - how to prevent overwriting class methods with variables in constructor

I have a large code base where some class members are set twice - once as a method, and the other explicitly in the constructor.
Here is a an example of what this might look like:
class SuperHero {
public name: string;
constructor(name: string) {
this.name = name;
// This line is a problem.
this.hasCape = () => {
return this.name === 'Batman';
};
}
// I want this to be the canonical implementation.
public hasCape() {
return this.name === 'Batman' || this.name === 'Wonder Woman';
}
}
It looks like public readonly hasCape() is invalid syntax.
Is there a way to enforce the method declaration as canonical at the compiler or linter level?
Inspired by the comment from Aaron Beall. This makes hasCape a property, that's a function, that's readonly. The typescript compiler then throws an error when assigning it from the constructor.
public get hasCape() {
return () => this.name === 'Batman' || this.name === 'Wonder Woman';
}

Saving a property and having a getter at the same time [duplicate]

This question already has answers here:
Private properties in JavaScript ES6 classes
(41 answers)
Closed 4 years ago.
I am trying to have a private property inside my class. I have a class called Person and an instance of that class: person declared with let person = new Person('name1').
I would like to save the name in person's properties. I could simply do:
class Person {
constructor(name) {
this.name = name;
}
}
But I also want to perform some actions when changing this value, so I use a Setter:
class Person {
set name() {
// some actions
}
constructor(name) { }
}
But then how do I save the name? I would have to have another property for example _name that would be used to save the actual value
class Person {
set name(newName) {
// some actions
return this._name;
}
set name(newName) {
this._name = name;
// some actions
}
constructor(name) {
this._name = name;
}
}
The problem is that _name can be accessed outside with person._name.
Is there a way to make it not accessible from outside?
I took inspiration from this answer (which doesn't use a getter and setter) and tried to enclose _name when defining the getter and setter. The following code doesn't work:
class Person {
constructor(name) {
var _name = name;
Object.defineProperties(this, {
"name": {
"get": () => { return _name; },
"set": () => { _name = name; }
}
});
}
}
"set": () => { _name = name; }
You just have a small mistake here. Should be:
"set": (newName) => { _name = newName; }

Typescript overriding extended property within constructor

I'm having an issue with Typescript where I extend a class and override a property from the super, however the super class property is still read in the constructor when I instantiate the sub class. Please see the below example:
class Person {
public type:string = 'Generic Person';
public constructor() {
console.log(this.type);
}
}
class Clown extends Person {
public type:string = 'Scary Clown';
}
var person = new Person(), // 'Generic Person'
clown = new Clown(); // 'Generic Person'
console.log(person.type); // 'Generic Person'
console.log(clown.type); // 'Scary Clown'
My expected behaviour would be 'Scary Clown' when I instantiate an instance of Clown. Is there another way I can achieve this without passing the values into the constructor itself or having some sort of init method that I fire manually after instantiating?
Thanks in advance :)
Property initializers are inserted right at the top of the constructor before the manually entered body of the constructor. So
class Person {
public type:string = 'Generic Person';
public constructor() {
console.log(this.type);
}
}
Becomes
var Person = (function () {
function Person() {
this.type = 'Generic Person';
// NOTE: You want a different value for `type`
console.log(this.type);
}
return Person;
})();
As you can see there is no way to get a different type in the parent constructor body using a property initializer.
Alternatively don't use type and rely on built-in constructor property:
interface Function{name?:string;}
class Person {
public constructor() {
console.log(this.constructor.name);
}
}
class Clown extends Person {
}
var person = new Person(), // 'Person'
clown = new Clown(); // 'Clown'
console.log(person.constructor.name); // 'Person'
console.log(clown.constructor.name); // 'Clown'

Categories

Resources