Overwriting a variable in another file using nodejs - node.js

I have a business scenario which is equivalent to below tricky situation. Hence putting this problem across in a simple way as below.
File1.ts
import * from 'something';
export const var1="value of var1";
//lets say we have a variable 'x' and this needs to be exported too. However value of x is still unknown.
export const x;
File2.ts
import * from 'something';
//set the value of 'x' in File1.ts as 5
File3.ts
import * from 'something'
//I should be able to get the value of 'x' from File1.ts. But it should be equal to the value set by File2.ts which is 5
As mentioned above, I should be able to set the value of x from somewhere (in this case, File2.ts) and everytime I use 'x' from File1.ts, be it in File3.ts or any other file, the value of 'x' should be 5 (set from File2.ts)

File1.ts
var x = 99 //some unknow value
function setValueOfX(value){
x = value
}
function getValueOfX(){
return x
}
module.exports = {
setValueOfX,
getValueOfX,
}
File2.ts
const File1 = require('./File1.ts')
File1.setValueOfX(5) /// you can set the value of x using the function
File3.ts
const File1 = require('./File1.ts')
console.log(File1.getValueOfX()) /// you can get value of x by using .getValueOfX function

Related

Typescript custom compile time validation types

Is there any way that we can define types that are checked during typescript compile time only. I want user to define a value to variable (ie not going to change on runtime) and i want to check if that value matches some criteria. For example, user need to set numeric value but cannot set less then 5, or set an string with specific format or validate with regex eg email. or string that must follow specific format or it can be pass through some condition and pass the test or else throw the error with defined message
Is there any way to achieve this in typescript??
Numeric value
You are allowed to create a union of allowed numeric values. But then you have to set maximum allowed value and compute range. See this answer and my article.
Here you have small example:
type MAXIMUM_ALLOWED_BOUNDARY = 999
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? [...Result, Result['length']][number]
: ComputeRange<N, [...Result, Result['length']]>
)
type NumberRange = ComputeRange<MAXIMUM_ALLOWED_BOUNDARY>
type Except<N extends number, CustomRange extends number> = Exclude<CustomRange, N>
type GreaterThanFive = Except<ComputeRange<5>, NumberRange>
const less: GreaterThanFive = 2 //expected error
const greater: GreaterThanFive = 6 // ok
Playground
String with specific format.
You can use template literal strings
type SpecificFormat = `${string}-${string}`
type StringDigit = `${number}`
const str: SpecificFormat = 'hello-world' // ok
const str2: SpecificFormat = 'hello world' // expected error
const strDigit: StringDigit = '42' // ok
const strDigit2: StringDigit = '42a' // expected error
However, if you want to apply more advanced restrictions, for instance check whether it is a valid HEX value or email you need to use duplicate variable value in a type or use extra dummy function. See example:
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? Result[number]
: ComputeRange<N, [...Result, Result['length']]>
)
type HexNumber = `${ComputeRange<10>}`
type HexString =
| 'A'
| 'B'
| 'C'
| 'D'
| 'E'
| 'F'
| 'a'
| 'b'
| 'c'
| 'd'
| 'e'
| 'f'
type Hex = `${HexNumber}` | HexString;
type StringLength<
Str extends string,
Acc extends string[] = []
> =
(Str extends `${infer S}${infer Rest}`
? StringLength<Rest, [...Acc, S]>
: Acc['length'])
type ValidateLength<
Str extends string,
Length extends number
> =
(StringLength<Str> extends Length
? Str
: never)
type WithHash<T extends string> = `#${T}`
type ValidateHex<
Color extends string,
Cache extends string = '',
> =
Color extends `${infer A}${infer Rest}`
? (A extends ''
? WithHash<Cache>
: (A extends Hex
? ValidateHex<Rest, `${Cache}${A}`>
: never)
) : WithHash<Cache>
const hex: ValidateHex<'ffffff'> = '#ffffff' // ok
const hex2: ValidateHex<'fffffz'> = '#ffffff' // expected error
Playground
If you want to validate function arguments you can check this answer, this answer or my article
If you are interested in email validation you can check this answer or my article
Also it is possible to apply restriction where all chars should be lowercased or uppercased, fir this purpose you can use built in intrinsic utility types:
// credits goes to #jcalz https://stackoverflow.com/questions/68963491/define-a-typescript-type-that-takes-a-lowercase-word#answer-73732194
let str: Lowercase<string>;
str = "abc"; // okay
str = "DEF"; // error in TS4.8+
However, it works only for TS 4.8 +. See my article or this answer

Why does this loop repeatedly log the last pair in the array instead of all the pairs?

I am using Node v16.15.1 and TypeScript v4.7.4
I want to split an object into multiple objects, and then insert each object as a value in another object.
i.e.
{key1:"value1", key2:"value2"}
-> {key1:"value1"} and {key2:"value2"}
-> {key3:"value3", key4:"value4", key5:{key1:"value1"}} and {key3:"value3", key4:"value4", key5:{key2:"value2"}}
Below is the code I am using:
let a:any = {}
let entries = Object.entries({key1:"value1", key2:"value2"});
for(const el of entries) {
let b = a;
b.key = Object.fromEntries(new Map([el]));
console.log(b.key);
console.log(b)
}
However, the output I get is this.
{key2:"value2"} is in both objects, instead of just the second one.
If I use the following code, however, I get the correct result:
let entries = Object.entries({key1:"value1", key2:"value2"});
for(const el of entries) {
let b:any = {};
b.key = Object.fromEntries(new Map([el]));
console.log(b.key);
console.log(b)
}
The problem with this is that I am not inserting into a blank object, and am passing it as a parameter in a function.
Why does this happen?
How would I be able to fix this?
TIA
In javascript, when you do let a:any = {}; and then let b = a; you are assigning to b the references of a (not the value). So if you update b, you are actually updating a because both variable are the same.
If you want b to be a copy of a you should do something like : let b = {...a}.

How can I dynamically create a variable dynamically in the current scope in node.js?

I'm trying to dynamically create node.js variables that point to objects.
I know I can create a variable dynamically in scope using eval:
var vars = ['a','b']
for(var n=0; n<vars.length; n++) {
eval('var '+vars[n]+' = '+n)
}
console.log(b) // prints 1
The above dynamically creates variables and gives them a value of whatever their index is inside the vars list.
But what if I want to set these dynamic variables to an object reference? Something like the following:
var vars = {a: {}, b:{}}
for(var k in vars) {
eval('var '+k) // create the variable dynamically
new Function('value', k+' = value')(vars[k]) // attempt to set the value
}
a.b = 5
console.log(vars.a.b) // undefined : (
I know why the above doesn't work - the function created by new Function can't see the current scope, and so can't set the value. Is there a way to do what I'm trying to do, such that console.log(vars.a.b) would print "5" rather than "undefined"?
UPDATE:
Hmm, I was wrong that new Function can't see or modify variables in the local scope, since this works:
var obj = {}
eval('var x')
new Function('value', 'x = value')(obj)
obj.a = 5
console.log(x.a) // prints 5
So now I'm pretty confused why my loop above doesn't seem to work..
UPDATE 2:
I just realized that my code actually does work in chrome's console. But its not working in node.js...
UPDATE JUST FOR PHIL:
Here's my situation. I'm using Parsimmon to build a parser combinator. This is how that's done:
var L = Parsimmon.createLanguage({
combinator1: function() {
return Parsimmon.string('hi')
},
combinator2: function() {
return L.combinator1.many()
}
})
I'd like to eliminate the need to write L. before every parser combinator I write. I could do this:
var combinator2 = L.combinator2
But that would require me to add an additional line like that for every combinator I write. As you can see, I can't use with since L is created after I'd be able to write with(L) and if I define my functions below then use them in the object, I'm back to duplicating those function names every time i write a new combinator.
So to summarize, I'd like to loop through L and put all the generated parser combinators into a nice clean variable in scope so I can write combinator1 instead of L.combinator1 (etc).
IIUC, whether or not there are better ways to achieve your goal, if you just remove 'var ' on the dynamic Function, it will operate on the outer (global) scope.
Change:
new Function('value', k+' = value')(vars[k])
to:
new Function('value', k+' = value')(vars[k])
So:
var vars = {a: {}, b:{}}
for(var k in vars) {
eval('var '+k) // create the variable dynamically
new Function('value', k+' = value')(vars[k]) // attempt to set the value
}
a.b = 5
console.log(vars.a.b)
You don't want to declare a new variable with local scope inside the function, you want to operate on the outer scope.
Update to address new question
Your first loop does work. Try introspecting on a or b; they are as should be expected, 0 and 1, respectively.
Update 2 based on info this is for Node.js
Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function , Function always works on the global scope. In Node, this is on global and var variables are not the global scope but are the module's scope. To fix this for Node, you can do the following and omit your eval var declaration (which was overriding for the module the global scope which you have access to inside Function):
var vars = {a: {}, b:{}}
for(var k in vars) {
new Function('value', k +' = value')(vars[k]) // attempt to set the value
}
a.b = 5
console.log(vars.a.b) // 5
In other words, the inner function sets variables which automatically become accessible via global, so your module code, in the absence of any module-scoped var declarations of a overwriting the global, you can set the global a properties as with the line a.b = 5.
Update 3
Since I had just been addressing your issue in understanding Function, I gave the above information. As per your follow-up comment (and again, without speaking to its suitability for your specific use case), you can operate on the object via eval as follows:
var vars = {a: {}, b:{}}
for(var k in vars) {
eval('var '+k+' = vars["'+k+'"]')
}
a.b = 5
console.log(vars.a.b) // 5
But to reiterate the warnings made by others--using eval is generally not a good idea and can be dangerous when the variables referenced include arbitrary user data...
change this line :
from :
a.b = 5
to
vars.a.b = 5
because a is undefined in your case that's why it is now allowing to create a new property
vars.a will return you a object not only a as a is vars property.

single line console output as a variable changes instead of one console.log per variable value?

Is there means in node.js to advance a counter within the console display to a single line, instead of a console.log output per line?
e.g.
let x = 1
while (x <= 10) {
console.log(`The value assigned to 'x' is now: ${x}`);
x++;
}
prints 10 lines for x = 1 through 10.
Is it possible instead to have a single line which remains static as the x value increments? As a use case, if the value of x incremented to one million, the console would display the one line until x was 1000000.
This does the trick for a single line:
const process = require('process');
let x = 1;
process.stdout.write(`The count is now at: ${x}`);
const counter = () => {
process.stdout.clearLine();
process.stdout.cursorTo(0);
x++;
process.stdout.write(`The count is now at: ${x}`);
if(x >= 10) {
clearInterval(cycle);
process.stdout.write('\n');
}
};
const cycle = setInterval(counter, 1000);
...and then there's this: https://github.com/sindresorhus/log-update

Swift 3 references

When creating an instance of an object, I'm having trouble setting its properties if I assign the property to another variable.
Eg. For an object containing nested objects, I want to assign one of the children to a temporary var to make it easier to work with.
Instead of doing this (which works):
myObj.myChildObject[0].someOtherChild[0].property = "something"
I'm trying to do:
var t = myObj.myChildObject[0].someOtherChild[0]
t.property = "something"
// this doesn't throw an error but doesn't change the value of myObj
What gives?
Edit>
Here's a contrived example to illustrate:
class Car { var name: String = "" }
var merc = Car()
var obj = merc.name
merc.name = "C63 AMG"
obj = "E300"
print("merc.name: \(merc.name)") // prints merc.name: C63 AMG
print("obj.name: \(obj)") // prints obj.name: E300
var ob2 = merc
ob2.name = "Toyota"
print("ob2.name: \(ob2.name)") // prints ob2.name: Toyota
print("merc.name: \(merc.name)") // prints merc.name: Toyota
So assigning the class instance to a var creates a reference. But assigning a property of that object to another var creates a copy?
I read through https://developer.apple.com/swift/blog/?id=10 and still don't get it :(
In the above, 'obj' is not a struct, enum or tuple, so shouldn't it be a reference type?
If myObj.myChildObject[0].someOtherChild[0] is a value type (I.e. a strict, direct enum or tuple), it's being copied upon assignment to t. Subsequent mutations on t only mutate that copy, and the original instance are unchanged.
You would have to reassign t back in:
var t = myObj.myChildObject[0].someOtherChild[0]
t.property = "something"
myObj.myChildObject[0].someOtherChild[0] = t
This is discussed in the Swift language guide.

Resources