SyntaxError: Unexpected Token '?' discord.js - node.js

I'm using discord.js version 12.5.3, I also am using replit for my project. I keep getting this error:
This is my code:
export default class Deps {
static #instances = new Map();
static get(type) {
return this.#instances.get(type)
?? this.add(type, new type());
}
static add(type, instance) {
return this.#instances
.set(type, instance)
.get(type);
}
}

Short answer: The ?? needs to be on the same line as the return statement:
export default class Deps {
static #instances = new Map();
static get(type) {
return this.#instances.get(type) ?? this.add(type, new Type()); // <-- Like this
}
static add(type, instance) {
return this.#instances
.set(type, instance)
.get(type);
}
}
Longer answer: The return statement in JavaScript has special automatic semicolon insertion ("ASI") rules which mean you need to have the entire expression on a single line, or use parentheses so that your return statement's expression clearly spans multiple lines.
So you could also do this:
export default class Deps {
static #instances = new Map();
static get(type) {
return ( this.#instances.get(type) // <-- Opening `(` here.
?? this.add(type, new Type())
); // <-- Closing `)` here.
}
static add(type, instance) {
return this.#instances
.set(type, instance)
.get(type);
}
}
Before I started using TypeScript I used to get stung by return ASI rules all the time without realising it: it's a frequent source of bugs.

Related

how can I use "lang" in gjs?

I'm working on Gnome shell extension recently. I looked at some code, like this:
const Lang = imports.lang;
const extension = new Lang.Class({...})
I can't find any information about Lang in GJS.
Where should I go to find the relevant development manual?
Don't use Lang anymore; it's deprecated and there are better ways. It was created before Function.prototype.bind() and ES6 Classes. Some reading:
GObject Basics
Legacy Class Syntax
Migrating GNOME Shell Classes
Signal Callbacks
// NOTE: the emitting object is always the first argument,
// so `this` is usually bound to a different object.
function myCallback(sourceObject, arg1) {
if (this === sourceObject)
log('`sourceObject` is correctly bound to `this`');
}
// OLD
sourceObject.connect('signal-name', Lang.bind(myCallback, sourceObject));
// NEW
sourceObject.connect('signal-name', myCallback.bind(sourceObject));
GObject Classes
// OLD
const MyLegacyClass = new Lang.Class({
GTypeName: 'MyLegacyClass',
Extends: GObject.Object,
_init(a, b) {
this.parent(a);
this.b = b;
}
});
// NEW
const MyClass = GObject.registerClass({
GTypeName: 'MyLegacyClass',
}, class MyClass extends GObject.Object {
_init(a, b) {
super._init(a);
this.b = b;
}
);

How can I declare variable for a module in TypeScript?

I have two files: index.ts and A.ts
A.ts:
export default class {
do() {
console.log(someVar);
}
}
index.ts:
import A from './A';
function printIt(param) {
let someVar = param;
let a = new A();
a.do();
}
printIt('wow'); // Console output: wow
printIt('123'); // Console output: 123
Is it real to declare someVar for A.ts from index.ts without wrapping A class?
I know that Node.JS wrappes all modules in (function (exports, require, module, __filename, __dirname, process, global) { }: How to change the Node.js module wrapper?
I tried to make a custom require function and pass my var like an argument. But I don't understand how can I make own require function in TypScript. Are there any ideas?
The scope of variables depends on where they are defined, not where they are called. this is on purpose, so you do not accidentally call on variables you did not know about being in the same scope as your function's invocation.
You must explicitly tell the code you want to pass this new variable into it, either just like Lux showed, or through passing it to the function like:
export default class {
do(someVar) {
console.log(someVar);
}
}
function printIt(param) {
let someVar = param;
let a = new A();
a.do(someVar);
}
what you're trying to do is akin to having everything be a global variable.
if you MUST do this (you shouldn't), there is one way you can.
export default class {
do() {
console.log(global.someVar);
}
}
function printIt(param) {
global.someVar = param;
let a = new A();
a.do();
}
There's many reasons why you do not want to do global variables, here are some
Edits after clarification:
So the "this" keyword inside of a module refers to the module's global scope, so I tried the following snippet:
// modA.js
const moduleContext = this
class ExportedClass {
printer() {
console.log(moduleContext.someVar)
}
}
module.exports = { ExportedClass }
//modB.js
let A = require("./modA")
A.someVar = "hello world"
let obj = new A.ExportedClass()
obj.printer()
and it seems the context was removed, the same thing with ES6 imports using mjs files, what did Work however is this:
//modA.js
function printer() {
console.log(this.someVar)
}
module.exports = { printer }
//modB.js
let A = require("./modA")
A.someVar = "hello world"
A.printer()
it seems moduleContext points to the old module context object, and the new imported module has a different context object.
This still seems like a bad idea though, you're better off structuring your code so that you export a constructing function, that takes whatever needs to be "global" for that scope, and sets it inside.
What are you trying to do? The seperation for module is on purpose, so the scope of everything remains.
Next, you have a typo: it should probably be let a = new A(); not let a = new A;.
But why dont you just pass the variable as an argument to the constructor of your A class?
export default class {
someVar: string;
constructor(someVar) {
this.someVar = someVar;
}
do() {
console.log(this.someVar);
}
}
now you can just do
function printIt(param) {
let someVar = param;
let a = new A(someVar);
a.do();
}

Does nodejs requires bind class method?

I am using node 12 in my project. Back to 2 years ago, I remember I need to bind method for class instance method like below:
class Logger {
constructor () {
this.printName = this.printName.bind(this);
}
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
But recently I found I don't need to call bind in the constructor. Does the latest node version support auto-bind already?
The behavior hasn't changed. The situation in which you need to .bind is when the instance's printName method would otherwise get called without a calling context. For example:
class Logger {
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
or with, instead of fn:
setTimeout(l.printName)
or with:
button.addEventListener('click', l.printName)`
In all of these situations, an error will be thrown if you don't use .bind, because the method gets called without a calling context - but the calling context of the Logger instance is needed for this to refer to the instance, so that this.print refers to the print method of the instance.
This sort of thing has always been true in Javascript. Nothing's changed in the past few years, except that it's now a bit easier to bind - you can use new class field syntax instead of having a constructor:
class Logger {
printName = (name = 'there') => {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();

Node + ES6 classes: Setting up a set of cached objects

I've tried to search for instance caching and singletons on Google and StackOverflow without success, seeing only posts about module.exports, if you know a post that answers this question, feel free to reference it. Thank you!
I have an application that needs to work on a set of objects that rarely change, and hence need to be cached for performance optimisation.
Here is a toy example where a single property is set directly.
When I call the application, I export an object that will contain the set of cached objects in assets_cached.js:
const Assets = {};
module.exports.Assets = Assets;
In another module of the application I have an ES6 class:
const _ = require('lodash')
const { Assets } = require('./assets_cached')
class Asset {
constructor(id, some_property) {
if (id in Assets) {
// Update instance data with cached properties
_.assign(this, Assets_cached[id]);
} else {
// If it's not cached, create a new object
this.id = id;
this.some_property = some_property;
// Cache this object
Assets_cached[id] = this;
}
}
getProperty() {
return this.some_property;
}
setProperty(value) {
this.some_property = value;
// Is there a way of avoiding having to do this double assignment?
Assets_cached[id].some_property = value;
}
}
module.exports = Asset;
How may I avoid having to set the some_property twice (in the current instance and the cache, while ensuring that other instances are updated in parallel)?
Ideally I'd like to do something like:
if (id in Assets) {
this = Assets.cached[id]
}
inside the constructor, but this is not possible.
What's the most elegant and correct way of making this work?
Ideally I'd like to do something like this = Assets.cached[id] inside the constructor
The magic keyword here is return. You can just return an arbitrary object from the constructor and it will be used instead of this.
constructor(id, some_property) {
if (id in Assets) {
// use cached instance instead of creating a new one
return Assets_cached[id];
} else {
this.id = id;
this.some_property = some_property;
// Cache this object
Assets_cached[id] = this;
}
}
Here is the approach to the comment that was made some half an hour ago ...
const { Assets_cached } = require('./assets_cached');
// const { AssetStore } = require('./assetstore');
class Asset {
constructor(id, some_property) { // clean/lean constructor.
this.id = id;
this.some_property = some_property;
}
getProperty() {
return this.some_property;
}
setProperty(value) {
this.some_property = value;
}
}
function isAsset(type) {
// poor man's approach ... change to something more feasible.
return (type instanceof Asset);
}
function createAsset(id, some_property) { // factory that also handles caching.
var
asset = Assets_cached[id];
// asset = AssetStore.get(id);
if (!(asset && isAsset(asset))) {
asset = Assets_cached[id] = (new Asset(id, some_property));
// AssetStore.put(id, (asset = new Asset(id, some_property)));
}
return asset;
}
module.exports = {
create : createAsset,
isAsset : isAsset
};
Note
One also should consider providing a minimal API to Assets_cached, something like put/set, get and delete instead of Assets_cached being an entirely exposed, plain key-value store.

How to create node.js module using Typescript

The very simple module that I've created to test the viability of this endeavor. Here is the beginning of SPServerApp.ts:
class SPServerApp {
public AllUsersDict: any;
public AllRoomsDict: any;
constructor () {
this.AllUsersDict = {};
this.AllRoomsDict = {};
}
}
module.exports = SPServerApp();
Then in my app, I have this require statement:
var serverapp = require('./SPServerApp');
I then try to access one of the dictionaries like so:
serverapp.AllUsersDict.hasOwnProperty(nickname)
But get the error:
TypeError: Cannot read property 'hasOwnProperty' of undefined
Can anybody see what I am doing wrong here?
Thanks, E.
The problem is that you forgot the 'new' keyword when calling the constructor. The line should read:
module.exports = new SPServerApp();
If you don't use new your constructor will be treated as a normal function and will just return undefined (since you did not return anything explicitly). Also 'this' will not point to what you expect within the constructor.
Omitting new in Node is actually quite common. But for this to work you have to explicitly guard against new-less calls in the constructor like so:
constructor () {
if (! (this instanceof SPServerApp)) {
return new SPServerApp();
}
this.AllUsersDict = {};
this.AllRoomsDict = {};
}
BTW, in TypeScript you can also use module syntax. The TS compiler will translate this into the export/require statements. With ES6 style modules your example would look like this:
export class SPServerApp {
public AllUsersDict: any;
public AllRoomsDict: any;
constructor () {
this.AllUsersDict = {};
this.AllRoomsDict = {};
}
}
export var serverapp = new SPServerApp();
In your other TS file you just import:
import { serverapp } from './SPServerApp';
serverapp.AllUsersDict.hasOwnProperty('something');

Resources