Office Scripts: class constructor() does not work - office-scripts

i'm trying to use class on Office Scripts (Excel Online). constructor() produces "Unexpected strict mode reserved word". could someone help me?
function main(workbook: ExcelScript.Workbook)
{
class Foo{
constructor(){
console.log("Foo!");
}
}
const foo = new Foo();
}
code editor screenshot "Unexpected strict mode reserved word"

It looks like that operation isn't allowed in the constructor. You can provide a string in the object's constructor, assign that to a private field in the class, and then print that string using a method. So something like:
function main(workbook: ExcelScript.Workbook) {
class Foo {
private foo : string
constructor(foo) {
this.foo = foo;
}
bar() {
console.log(this.foo)
}
}
const foo = new Foo("Foo!");
foo.bar() //Foo!
}

Related

Nodejs Calling the class multiple times

I have simple class like that;
class Foo {
constructor() {
this.datas = {}
}
set(key, data) {
return this.datas[key] = data
}
get(key) {
return this.datas[key]
}
}
module.exports = Foo
I am adding some data to datas veriable first. But when I call same class in the next time, veriable is not saving like that;
const foo1 = Foo()
foo1.set('a',[1,2,3])
const foo2 = Foo()
var aData = foo2.get('a')
console.log(aData)
But data not getting. How can I fix it?
The datas property that you defined in the Foo class is not being saved between instances of the class, because it is defined inside the constructor function. This means that every time you create a new Foo object with const foo = new Foo(), a new datas property will be created for that object, and it will not be shared with other instances of the Foo class.
if you want to shared by all instances of the class.refer Javascript ES6 shared class variable
You can pass your object into another class constructor,
https://stackblitz.com/edit/node-k3vqtp?file=index.js
or use global variable
global.foo = new Foo();
global.foo.set('a', [1, 2, 3]);
or use package like InversifyJS to inject the class
...
#injectable()
export default class A implements IA {
private _foo!: Foo;
public get foo(): Foo {
return this._foo;
}
public set foo(v: Foo) {
this._foo = v;
}
constructor(
#inject(TYPES.Foo) foo: Foo,
) {
this.foo = foo;
}
...
Due to the limited information from your question, here only list some options. You can look for the best way to fit your scenario.

How to extends a class of a module?

I am using modern Javascript (EC6+) code with node --experimental-modules.
import bigInt from 'big-integer'; // npm i big-integer
console.log(bigInt(333).toString(2)) // fine
class bigIntB4 extends bigInt {
constructor(...args) {
super(...args);
}
test() {
console.log("Hello!")
}
}
let c = new bigIntB4(333) //fine
console.log(c.toString(2)) // fine
c.test() // BUG!
Error: "TypeError: c.test is not a function"
bigInt is not a constructor function. It's a normal function that returns an object. As such you cannot really extend it.
Here is a simplified example of the issue:
function Foo() {
return {foo: 42};
}
class Bar extends Foo {
constructor() {
super();
}
}
console.log(new Bar instanceof Bar);
console.log(new Bar);
The value returned by new Bar is the value returned by Foo, which does not extend Bar.prototype.
If you need only to add a new method, at least, you can modify the prototype:
bigInt.prototype.test = function () {
console.log("Hello!");
};

Non type type parameters

What if I have classes that are different only by some constant used in code. Is it possible to have one generic implementation without runtime cost?
Here is the example (it's a little bit too long...)
#:enum abstract Param(Int) {
var foo = 0;
var bar = 1;
}
class WorkBase {
public function new() {}
private inline function work_impl(p: Param): Void {
if(p == foo) {
trace('foo');
}
else {
trace('bar');
}
}
public function work(): Void {
}
}
class WorkFoo extends WorkBase{
override public function work(): Void {
work_impl(foo);
}
}
class WorkBar extends WorkBase {
override public function work(): Void {
work_impl(bar);
}
}
class Test {
public static function main() {
var workFoo = new WorkFoo();
var workBar = new WorkBar();
workFoo.work();
workBar.work();
}
}
After compilation with -D analyzer-optimize we will see that WorkFoo.work() and WorkBar.work() functions were optimized and contain only one branch of code that matches one of the Param values. In real life there are lot of such comparisons in work_impl(), and they all are optimized out. That's good.
But what if I do not want to create WorkFoo and WorkBar by hand. Is it possible to do something like this:
#:generic
class WorkBase<PARAM> {
private inline function work_impl(p: Param): Void {
...
}
public function work(): Void {
work_impl(PARAM);
}
}
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
Const type parameters can be used without #:genericBuild - a const type parameter in combination with #:generic is enough to get the desired optimization:
#:enum abstract Param(Int) from Int {
var foo = 0;
var bar = 1;
}
#:generic class Work<#:const PARAM:Int> {
public function new() {}
public function work():Void {
if (PARAM == foo) {
trace('foo');
} else {
trace('bar');
}
}
}
class Main {
public static function main() {
var workFoo = new Work<0>();
var workBar = new Work<1>();
workFoo.work();
workBar.work();
}
}
Due to #:generic, one class is generated for each constant value, for instance on JS the output looks like this:
var Work_$0 = function() {
};
Work_$0.prototype = {
work: function() {
console.log("source/Main.hx:11:","foo");
}
};
var Work_$1 = function() {
};
Work_$1.prototype = {
work: function() {
console.log("source/Main.hx:13:","bar");
}
};
Note that this example fails with a "constraint check failure" in Haxe 3.4.7 for some reason, but works fine with Haxe 4 preview 4 and later. Another limitation is that neither new Work<Param.foo>() nor new Work<foo>() work - you need to pass the actual constant value.

declare 'this' value for helper function

I have a class:
const helper = function(val){
console.log(this.a);
console.log(this.b);
this.bar();
};
export class Foo {
public b = '45'
private a = 15;
bar(){
}
myMethod(){
return helper.apply(this,arguments);
}
}
the problem is, in the helper function, it doesn't know what the context is (what the value of 'this' is).
Is there a way for me to tell typescript that the value for this in the helper function is an instance of Foo?
(the reason I use the helper function is to create true private methods).
Try adding this on top of your helper function:
let self: Foo = this as Foo;
// use self instead of this below
Alternatively, you could replace all instances of this in it with (this as Foo).
You can declare the type of this for any function by adding an extra parameter named this. The this parameter will not be emitted to Javascript, it will be just for the benefit of the compiler to be able to type check your code:
const helper = function(this: Foo, val: number){
console.log(this.a); /// error a is private
console.log(this.b);
this.bar();
};
This will not however break encapsulation, you will still not be able to access private properties from outside the class, so unless you create the function inside the class it will still give an error as above. For functions defined inside the class it will not give errors:
export class Foo {
public b = '45'
private a = 15;
bar() { }
createHelper() {
return function (this: Foo, val: number) {
console.log(this.a);
console.log(this.b);
this.bar();
};
}
myMethod() {
return this.createHelper().apply(this, arguments);
}
}

constraint on static fields and type inference

Is it possible to have constraint on static fields in Haxe? For example we may have classes which have static field instance of type of corresponding class. And we may want a function that will return an instance of class passed as parameter. This is my attempt:
class Foo {
static public var instance = new Foo();
function new() {}
}
class Test {
// get instance from every class that have static field instance
static function getInstance<T, ClassT:({instance:T}, Class<T>)>(t:ClassT):T {
return t.instance;
}
static function main() {
var a = getInstance(Foo);
$type(a); //Test.hx:14: characters 14-15 : Warning : Unknown<0>
}
}
but it fails, because type parameter constraints are checked lazily. Any ideas on how do this?
Have you considered using a typedef?
Heres a quick edit of your code showing the basic idea
typedef HasInstance = {
var instance:Dynamic;
}
class Foo {
static public var instance = new Foo();
function new() {}
}
class Bar {
static public var instance = new Bar();
function new() {}
}
class Test {
// get instance from every class that have static field instance
static function getInstance<T:HasInstance>(t:T):T {
trace(t);
return t.instance;
}
static function main() {
var a = getInstance(Foo);
trace(a);
$type(a);
var b = getInstance(Bar);
trace(b);
$type(b);
}
}
example on try haxe!
You would change the instance type within the typedef to be more appropriate for your needs, and you can also constrain typedefs too, which can be very useful
If you don't mind using macro, here is a possible solution:
http://try-haxe.mrcdk.com/#7d650
Foo.hx
class Foo {
static public var instance = new Foo();
public var foo:Int;
function new() {}
}
class Test {
macro static function getInstance(e) return Macro.getInstance(e);
static function _getInstance<T, ClassT:({instance:T}, Class<T>)>(t:ClassT):T
return t.instance;
static function main() {
var a = getInstance(Foo);
$type(a);
}
}
Macro.hx
import haxe.macro.Expr;
import haxe.macro.Context.*;
using tink.MacroApi;
class Macro {
public static function getInstance(e:Expr) {
var ct = TPath(e.toString().asTypePath());
return macro (Test._getInstance($e):$ct);
}
}

Resources