Assign fields of class with object keys in typescript/JS - node.js

I need to dynamically update the fields of this class dynamically with an object
export default class Foo {
private accessKey: string;
private workspaceId: string;
private api: AxiosInstance;
public bar: string;
public name: string;
...
...
private async fetch() {
try {
// data contains bar and name value
const { data } = await this.api.get("/");
// goal
this = {...this, ...data};
See goal comment, how can I do this dynamically?

Assignments and this
Why assigning to this is disallowed
Disregarding that it's not allowed, you don't want to reassign your this reference.
If it was allowed, we could write this confusing code:
const object = {
reassignSelf() {
this = {};
}
};
const ref = object;
object.reassignSelf();
/* Both ref and object are constant variables,
* so their values (references) should never change.
* But by reassigning `this` in object.reassignSelf,
* what value should this comparison produce?
*/
console.log(ref === object);
Then how to assign to this?
As implied earlier, we don't want to reassign this; we want to reassign its properties:
Static assignment. Example:
this.bar = data.bar;
this.name = data.name;
Dynamic assignment. Example:
Object.assign(this, data);

Use Object.assign
class X {
update(from: Partial<this>) {
Object.assign(this)
}
}

Related

NodJS how to get the Object a function belongs

some times code says it best. In below example code in Chain.add I have the function name and vars fed in to it. But I am trying to reference the object that the function is associated with. How can I do this
class Chainable {
constructor(...values) {
this._chainableConstruct={
name: this.constructor.name,
values
};
}
}
class Chain {
constructor() {
this.data=[];
}
add(func,vars) {
console.log(func.name); //returns fun
console.log(...vars); //returns test 45
console.log(func.parent); //return undefined want object t from line 28
}
}
class Test extends Chainable {
fun() {
console.log("fun");
}
}
let t=new Test();
let c=new Chain();
c.add(t.fun,["test",45]);
Out of the box, you can't. Furthermore, you can set property values of multiple objects with the same value, so the same function object might have multiple "parents".

Get filename of derived class from base class in typescript running on node.js?

I'm looking for a way to get the filename of a derived class from a base class in typescript running on node.js. An example of this would be:
Foo.ts
export abstract class Foo {
constructor() { }
name() { return (__filename); }
print() { console.log(this.name()); }
}
Bar.ts
import { Foo } from './Foo';
export class Bar extends Foo {
constructor() { super(); }
}
main.ts
import { Bar } from './Bar';
let bar = new Bar();
bar.print(); // should yield the location of Bar.ts
Due to the number of files involved and just cleanliness I'd like this to be confined to the Foo class rather than having an override of the name() function in each derived class.
I was able to sort-of solve this with the code:
private getDerivedFilePath(): string {
let errorStack: string[] = new Error().stack.split('\n');
let ret: string = __filename;
let baseClass: any = ThreadPoolThreadBase;
for (let i: number = 3; i < errorStack.length; i++) {
let filename: string = errorStack[i].slice(
errorStack[i].lastIndexOf('(') + 1,
Math.max(errorStack[i].lastIndexOf('.js'), errorStack[i].lastIndexOf('.ts')) + 3
);
let other: any = require(filename);
if (other.__proto__ === baseClass) {
ret = filename;
baseClass = other;
} else {
break;
}
}
return (ret || '');
}
Added to Foo, which will work when called from the constructor to set a private _filename property, for inheritance chains beyond the example above so long as the files are structured with a default export of the class being used. There may also be a caveat that if a base class from which a derived object is inheriting directly is initialized as a separate instance within the constructor of any member of the inheritance chain it could get confused and jump to another independent derived class - so it's a bit of a hacky work-around and I'd be interested if someone comes up with something better, but wanted to post this in case someone stumbles across this question and it works for them.
You can use require.cache to get all cached NodeModule objects and filter it to find your module.
https://nodejs.org/api/modules.html#requirecache
class ClassA {
public static getFilePath():string{
const nodeModule = this.getNodeModule();
return (nodeModule) ? nodeModule.filename : "";
}
public static getNodeModule(): NodeModule | undefined{
const nodeModule = Object.values(require.cache)
.filter((chl) => chl?.children.includes(module))
.filter((mn)=> mn?.filename.includes(this.name))
.shift();
return nodeModule;
}
}
class ClassB extends ClassA {
constructor(){}
}
const pathA = ClassA.getFilePath(); //Must return the absolute path of ClassA
const pathB = ClassB.getFilePath(); //Must return the absolute path of ClassB

Get promise value outside of scope nodejs

My script is
$scope.uid = '';
this.myService.getCount(response).then(function (value) {
$scope.uid = value;
});
I want value outside of this promise but I am getting error Cannot find name '$scope'
Have you try to have uid as a class member and if you shoud use outside your class scope you can define it as a static member.
If it is will not help you please provide more detailed information
class YourClass {
static uid: string = '';
static YourClassFunc() {
this.myService.getCount(response).then(function (value) {
YourClassFunc.uid = value;
});
}
}
https://www.tutorialsteacher.com/typescript/typescript-static

Typescript Class in NodeJS

I am trying to create and use some Data Classes in NodeJs which i defined in Typescript and are at a point where i am wondering if there is a simpler way.
In javascript i was able to do
let myBuilding = new Building
Then i was able to just do
myBuilding.col1 = "Wall"
myBuilding.col2 = "None"
and so on
in typescript it doesn't like it if i don't declare everything at the point of declaration. Is there a way to initialize a class with blank values and then assign them later ? Also what happens when there is something that doesnt get a value assigned ? in javascript we dont get that item returned which is great when parsing from json to a class
Here is what a class of mine looks like
export class Exterior {
public exterior: string;
public fencing: string;
public security: string;
public sewer: string;
public lot: string;
public pool: string;
public patioPorch: string;
public spa: string;
constructor(exterior: string, fencing: string, security: string, sewer: string, lot: string, pool: string,
patioPorch: string, spa: string) {
this.exterior = exterior;
this.fencing = fencing;
this.security = security;
this.sewer = sewer;
this.lot = lot;
this.pool = pool;
this.patioPorch = patioPorch;
this.spa = spa;
}
}
when you declare a type you can just make things optional:
class Building {
height?: number;
}
now typescript won't complain if you don't declare a height right away but you still can't add extra undeclared fields like width.
You can also declare things as a Partial<Building> if they meet some subset of the interface but not all of the required fields.
Here are four ways of achieving this:
class Foo {
// This will not do anything, so remove it
constructor() {}
// this will be undefined initially
private internalA!: number;
public get fieldA() {
return this.internalA
}
public set fieldA(internalAValue: number) {
this.internalA = internalAValue;
}
// this will be undefined initially
public fieldB!: boolean;
// this will be undefined initially
public fieldC!: string;
// this will be "example-initial-value" initially
public fieldD: string = "example-initial-value";
}
const foo = new Foo();
// Method 1 using setters
foo.fieldA = 2;
alert(foo.fieldA);
// Method 2 using simple assigning
foo.fieldB = true;
alert(foo.fieldB);
// Method 3 using Object.defineProperty
Object.defineProperty(foo, 'fieldC', {
value: "test",
writable: false
});
alert(foo.fieldC);
// Method 4 using Object.assign
Object.assign(foo, {fieldD: "hello"});
alert(foo.fieldD);
Be very careful or even avoid Object.defineProperty and Object.assign directly without creating a wrapper that enforces the types. They both have many ways of getting around / forgetting your type system.
setter method and direct public field assignment are the easiest type safe ways.
You can run it here
Here is a way for setting multiple things in one go without initialising first
interface IFooParams {
fieldA: number;
fieldB: boolean;
fieldC: string;
fieldD: string
}
class Foo {
// this will be undefined initially
public fieldA!: number;
// this will be undefined initially
public fieldB!: boolean;
// this will be undefined initially
public fieldC!: string;
// this will be "example-initial-value" initially
public fieldD: string = "example-initial-value";
public setAllInOneGo(params: IFooParams): void {
this.fieldA = params.fieldA;
this.fieldB = params.fieldB;
this.fieldC = params.fieldC;
this.fieldD = params.fieldD;
}
}
const foo = new Foo();
// Whenever:
foo.setAllInOneGo({
fieldA: 2,
fieldB: false,
fieldC: "hello",
fieldD: "world"
});

With TypeScript: unable to refer to 'this' (class) from inside a function

I'm learning TypeScript and have the following class:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(getCertificate)
.fail(somethingWrong);
function getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
}
As you can see on the above code, the first call to this refers to my class DetailDriver. That's good. The second call to this (inside getCertificate) refers to any. That's not what I need. I need to refer to my class DetailDriver.
How to proceed?
Thanks.
Well,
According to section 4.9.2 of the TypeScript Language Specification you should use fat arrow syntax to preserve the scoping for this.
return promise
.then(() => return.this.id;)
.fail(somethingWrong);
Then the this keyword is properly determined to be a Driver.
For reference, you could also just do:
class SomeClass {
public someMethod() {
// Do something
}
public anotherMethod() {
var that = this; // Reference the class instance
function someFunction () {
that.someMethod();
}
}
}
You could refactor to something like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(this.getCertificate.bind(this)) // <- important part
.fail(somethingWrong);
}
// new method function here
private getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
Using the function keyword anywhere in your class will make any reference to this keyword refer to that function rather than the outer class. Generally, you want to avoid defining functions inside of classes, unless you use the "fat arrow" syntax. That would look like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(() => { // <- important part
var id = this.driver.id(); // this refers to any
return ...
})
.fail(somethingWrong);
}
}

Resources