Attempted to assign to readonly property ECMAScript React Native - ecmascript-6

I am trying to assign a value to an array declared in my Component. Unfortunately, exception is thrown.
TypeError: Attempted to assign to readonly property
Even if I remove strict mode, still exception is being raised. Can please someone guide me how can I make a variable both readable and writable? Thanks..!
Code:
class RootView extends Component {
cachedData : []; //declared array here
//trying to assign dictionary in some function
someFunction(results) {
this.cachedData[this.state.searchString.length - 1] = results;
//exception raised here
}
}

Your syntax is incorrect. Add it to a constructor.
class RootView extends Component {
constructor() {
super();
this.cachedData = [];
}
someFunction(results) {
this.cachedData[this.state.searchString.length - 1] = results;
}
}
If your transpiler supports experimental code (stage 0), you can use the following:
class RootView extends Component {
cachedData = [];
someFunction(results) {
this.cachedData[this.state.searchString.length - 1] = results;
}
}

Related

How can I write a closure function in getter in ES6 ?

In ES5, I can write it like this:
MyClass.prototype.value = (function() {
var privateVariable = 0;
return function() {
return ++privateVariable;
};
})();
But in ES6, how can I do it ?
class MyClass {
get value() {
// return ??
}
}
A direct counterpart, which is not idiomatic to ES6 classes:
class MyClass {}
MyClass.prototype.value = (() => {
let privateVariable = 0;
return function() {
return ++privateVariable;
};
})();
There are no practical reasons to make privateVariable completely unavailable from the outer scope, especially since it doesn't play well with ES6 classes. This cannot be considered a proper encapsulation because privateVariable isn't available for reflection; it cannot act as protected member as well.
There can be private member that stores a value:
class MyClass {
constructor() {
this._value = 0;
}
value() {
return ++this._value;
}
}
It could be a symbol but this doesn't make class design more secure, just introduces additional complications when a class is inherited in another module:
// should be carried around everywhere to make the class extendable
export const VALUE = Symbol('value');
class MyClass {
constructor() {
this[VALUE] = 0;
}
value() {
return ++this[VALUE];
}
}
Note that get value() {} is not same thing as value() {}.
One of TypeScript (which is a superset of ECMAScript) benefits is the encapsulation that is enforced at compilation time.
The equivalent to the ES5
function MyClass() {}
var privateVariable = 0;
MyClass.prototype = {
get value() {
return ++privateVariable;
}
};
in ES6 class syntax would be
let privateVariable = 0;
class MyClass {
get value() {
return ++privateVariable;
}
}
Whether you put all that in an IEFE or module or whatnot for local scope doesn't matter, it's the same.

TypeError: Attempted to wrap undefined property as function

The example below is simplified. I have a getter method:
class MyClass {
constructor() {}
get myMethod() {
return true;
}
}
which is processed by babel. And I want to mock it like this:
var sinon = require('sinon');
var MyClass = require('./MyClass');
var cls = new MyClass();
var stub = sinon.stub(cls, 'myMethod');
stub.returns(function() {
return false;
});
But I get the following error:
TypeError: Attempted to wrap undefined property myMethod as function
And this happens on both version 1 and 2 of sinon library.
Its an issue with how you defined your method myMethod. When you use get to define a method, it actually is treated like a property and not a method. This means you can access cls.myMethod but cls.myMethod() will throw an error as it is not a function
Problem
class MyClass {
constructor() {}
get myMethod() {
return true;
}
}
var cls = new MyClass();
console.log(cls.myMethod())
Solution
You have to update your class definition to treat myMethod as a function like below
class MyClass {
constructor() {}
myMethod() {
return true;
}
}
var cls = new MyClass();
console.log(cls.myMethod())
With this change now your sinon.stub should work fine

Extend HTMLElement in TypeScript

I'm trying to extend the HTMLElement in typescript. I tried different methods and they all work, but i keep getting an type-script error:
Argument Sprite is not assignable to parameter type Node;
When i do :
document.body.appendChild(createSprite());
interface Sprite extends HTMLElement {
}
function createSprite() : Sprite {
return <Sprite> document.createElement("div");
}
document.body.appendChild(createSprite());
I ran this through the TypeScript Playground (and added some text so I could see the result) and it works fine:
interface Sprite extends HTMLElement {
}
function createSprite() : Sprite {
return <Sprite> document.createElement("div");
}
var sprite = createSprite();
sprite.innerHTML = 'Test';
document.body.appendChild(sprite);

Referencing own constructor in inner function

Here's a toy example distilled from a complex class:
public class MyClass {
public function MyClass() {
trace('Created');
}
public static function makeObjectAsync(callback:Function):void {
inner();
function inner():void {
var object:MyClass = new MyClass(); // line 10
callback(object);
}
}
}
After calling the static function:
MyClass.makeObjectAsync(function(object:Myclass):void { ... })
the following run-time exception occurs at line 10:
TypeError: Error #1007: Instantiation attempted on a non-constructor.
Why is this, and what can I do about it?
Edit
It appears that new (MyClass)() works. Now I'm possibly more confused.
Not too clear on the WHY to be honnest. It has to do with the scope inherited by anonymous functions, depending on how they are declared.
I have 2 solutions for you though.
If your makeObject method was not static, it would work.
Declare your anonymous function the other way :
public static function makeObjectAsync(callback:Function):void {
var inner : Function = function():void {
var object:MyClass = new MyClass();
callback(object);
};
inner();
}
You shouldn't call your variable "object". Why do you nested your inner function? Why don't you just:
public static function makeObjectAsync(callback:Function):void {
callback(new MyClass());
}
Or if you really want that nested function:
public static function makeObjectAsync(callback:Function):void {
inner();
function inner():void {
callback(new MyClass());
}
}
And you can't recall the class' constructor again, use a function which is called in the constructor then call it again. With this you aren't referencing the constructor but creating a new instance of the class.

Extending Object prototype in ActionScript 3

Whenever I try to extend the Object prototype, I get an error:
Error #1056: Cannot create property my_extension on mx.core.UIComponentDescriptor.
I searched around, and found these:
Flash AS3: ReferenceError: Error #1056: Cannot create property
ReferenceError: Error #1056 - instance name Error
I'm not using a visual IDE for designing a stage, but MXML and AS3 files, so I'm not sure what to make of this error.
My code:
Object.prototype.keys = function(): Array {
var keys: Array = [];
for (var key: * in this) {
keys.push(key);
}
return keys;
}
Object.prototype.values = function(): Array {
var values: Array = [];
for each (var value: * in this) {
values.push(value);
}
return values;
}
Using prototype to extend a class seems very ActionScript 1 or 2.
In AS3, you may be able to prototype if the class is dynamic.
There are downsides to prototype:
Only dynamic classes can be extended, one can not add methods to Math for example.
Calls to methods stored in the prototype take longer to execute.
Since methods are added at run-time, editors can not show them with code hinting or use the correct syntax highlighting.
Since all classes extend object, it is not necessary to explicitly declare Object as a base; however, you could define an AbstractObject class to be extended:
package
{
public dynamic class AbstractObject extends Object
{
public function AbstractObject()
{
super();
}
public function get keys():Array
{
var keys:Array = [];
for (var key:* in this)
{
keys.push(key);
}
return keys;
}
public function get values():Array
{
var values:Array = [];
for each (var value:* in this)
{
values.push(value);
}
return values;
}
}
}
Subtype AbstractObject for your classes.