Inaccessible method on TS object - javascript

I am attempting to make use of a method that is stored on a Typescript class from within a Vue component.
When attempting to use a method defined on said class from another class (which just so happens to be a Typescript Vue component), an Uncaught TypeError is returned to the console saying that the method I am trying to make use of is not a function
Consider the following Paper class:
export class Paper {
paperSize: number;
documentTitle: string;
constructor() {
paperSize = 1;
documentTitle = "Arbitrary title";
}
getDocumentRatio(): number {
return ArbitraryLibrary.arbitraryNumericFunction(this.paperSize);
}
}
When trying to use this class (the Vue component) in another class like:
#Component()
export class PaperUser {
paper = new Paper();
paperUserMethod() {
...
const unimportant = this.paper.getDocumentRatio();
...
}
...
// Wherever the method gets used
this.paperUserMethod();
...
}
Execution of the method is then interrupted, because using the function in this manner creates the TypeError
Initially thinking that this might be a binding issue I attempted something more like
...
this.paper.getDocumentRatio().bind(this.paper);
...
but evidently this does not work because binding in this way would be as effective as method chaining - with the IDE (VSCode) asserting that property 'bind' does not exist on type 'number'.

On first hand, you have to set your attribut in your constructor with this.myAttribut and on second hand you are using your method out of a method implementation of you class, you can try this :
class Paper {
paperSize: number;
documentTitle: string;
constructor() {
this.paperSize = 1;
this.documentTitle = "Arbitrary title";
}
getDocumentRatio(): number {
// try to be trivial on first attempt
return this.paperSize;
}
}
class PaperUser {
paper = new Paper();
paperUserMethod() {
return this.paper.getDocumentRatio();
}
usePaperuser(){
this.paperUserMethod();
}
}

Related

How to extend a parent class' instance variable in javascript

I am trying to extend a parent class's instance variable but flow js is complaining that this is not correct. Is there something I am missing?
// BaseClass
export type AdType = {
dom: HTMLElement,
};
export default class AdsRefresh {
ads: AdType[] = [];
constructor(configs) {
this.ads = configs;
}
}
// ChildClass
import type {AdType as BaseAdType, PlaceholderType} from './adsRefresh';
export type AdType = {
placeholderIndex?: number
} & BaseAdType;
class AdsRefreshTiler extends AdsRefresh {
ads: AdType[] = [];
constructor(configs) {
super(configs);
this.ads = this.getAds(configs);
}
}
Cannot extend `AdsRefresh` [1] with `AdsRefreshTiler` because property `placeholderIndex` is missing in `AdType` [2] but exists in object type [3] in property `ads`.Flow(InferError)
It doesn't look like Flow supports overriding types and is complaining about the type conflict for the "ads" field in the parent and the child. You aren't allowed to change the type of a field that's been defined in the parent in the child.
This is so the child parent relationship is maintained. If you change the type of one of the fields on a child class the functions that you defined in the parent may no longer function when you call them on the child.
e.g.
export default class Parent {
felid1: number;
parentFunction() {
return this.felid1 / 3;
}
}
class Child extends Parent {
field1: string; // Now the parentFunction wont work since you can't divide strings
}
var a = new Parent();
a.felid1 = 1;
a.parentFunction(); // Does not crash
var c = new Child();
c.field1 = "a";
c.parentFunction(); // Crashes
You'll have to restructure you objects so this doesn't happen. Either by breaking down ads into multiple fields or by not using extends.

Typescript decorate class add new method

I want to add a new method to a decorated class. Everything works well but the compiler complains that the method does not exist, how can I satisfy the compiler?
export function decorate( constructor : Function ) {
constructor.prototype.someMethod = function () {
}
}
#decorate
class Test {
constructor() {
//Property 'someMethod' does not exist on type 'Test'.
this.someMethod();
}
}
You could use:
(<any>this).someMethod();
or:
this['someMethod']();
You can't use interfaces to check that this contains method someMethod() because you're not in fact implementing the interface so I think these two are the only options...

How to access a method from a class from another class?

I want to use Object Oriented Programming technique with JavaScript but I can't access a method from one class from another class. How can do like the following?
class one{
write(){
console.log("Yes! I did!");
}
}
class two{
var object=new one();
tryingMethod(){
object.write();
}
}
I get the following error:
Uncaught SyntaxError: Unexpected identifier -->> for var object=new one();
Your syntax is not legal. There should be an error in your console showing you which line of code is not correct.
If it's a static method (doesn't use any instance data), then declare it as a static method and you can directly call it.
If it's an instance method, then you would typically create an object of type one and then call the method on that object (usually in the constructor).
To make the method static (which appears to be fine in your specific case):
class One {
static write(){
console.log("Yes! I did!");
}
}
class Two {
tryingMethod(){
One.write();
}
}
For the non-static case, you don't have the proper syntax. It appears you want to create the instance of the One object in a constructor for Two like this:
class One {
write(){
console.log("Yes! I did!");
}
}
class Two {
constructor() {
this.one = new One();
}
tryingMethod(){
this.one.write();
}
}
var x = new Two();
x.tryingMethod();
Note: I'm also following a common Javascript convention of using an identifier that starts with a capital letter for the class/constructor name such as One instead of one.
What I'd recommend doing is not tying the classes together so tightly and doing something like this...
class One {
write() {
console.log("Yes! I did!");
}
}
class Two {
constructor(one = new One()) {
this.one = one;
}
tryingMethod() {
this.one.write();
}
}
Now what you can do is...
const two = new Two();
two.write();
This allows you to have a better separation of concerns and allows you to more easily unit test the Two class because you can pass in a mock implementation of the One class if you want.
describe("two class", () => {
it("should do something", () => {
const one = {
write: sinon.spy()
};
const two = new Two(one)
two.tryingMethod();
expect(one.write.calledOnce).to.be.ok;
});
});
You can pack dependencies in a container.
class Provider {
private _one?: One;
private _two?: Two;
one(): One {
return this._one || (this._one = new One(this));
}
two(): Two {
return this._two || (this._two = new Two(this));
}
}
class One {
constructor(private provider: Provider) { }
write() {
console.log("Yes! I did!");
}
}
class Two {
constructor(private provider: Provider) { }
tryingMethod() {
this.provider.one().write();
}
}

Typescript: Type inference when using decorator

I wonder why when I use decorators or annotations in Typescript on a class. The compiler can't infer the new type of the class. If I don't use decorators and use the old way to do this in ES5 (ie. call manually the decorator) it obviously works.
For instance, here a sample that shows the issue:
function decorate(Target: typeof Base): IExtendedBaseConstructor {
return class extends Target implements IExtendedBase {
public extendedtMethod(): number {
return 3;
}
};
}
interface IBase {
baseMethod(): number;
}
interface IExtendedBase extends Base {
extendedtMethod(): number;
}
interface IExtendedBaseConstructor {
new(): IExtendedBase;
}
#decorate
class Base implements IBase {
public baseMethod(): number {
return 5;
}
}
const test = new Base();
test.baseMethod(); // OK
test.extendedtMethod(); // NOT OK, typescript think, Base is still Base but we decorated it.
With the older way, it works:
class Base implements IBase {
public baseMethod(): number {
return 5;
}
}
const ExtendedBase = decorate(Base);
const test = new ExtendedBase();
test.baseMethod(); // OK
test.extendedtMethod(); // OK
Thanks in advance.
Right now this doesn't work. There is a pending issue on github to allow class decorators to change the type of the class.
I would recommend doing the "old way" you mentioned until this is implemented.
There is a way to make this work with just a little extra coding required.
For any class decorator, create an interface with its properties and methods. Name it in a way so you can easily associate it with the decorator it's describing. In your case, it could be:
interface IDecorate {
extendedtMethod(): number;
}
For any class that needs this decorator, you simply create an interface with the same name as the class and let it extend all necessary decorator interfaces:
#decorate
#anotherDecorator
class MyClass {
// ...
}
interface MyClass extends IDecorate, IAnotherDecorator {}
Now, just turn off ESLint's or TSLint's warnings for empty interfaces and you should be ready to go. Any method or property added by the decorator will now be available to use within the decorated class itself.

Typescript call function from base class

is there a way to call a function from baseclass like overwrite.
Base Class
export class BaseClass {
constructor() {
//do something asynchronous
//than call initialized
}
}
Inheritance Class
export class InheritanceClass extends BaseClass {
initialized() {
// get called from base class
}
}
Do you mean like this:
class Base {
constructor(){
setTimeout(()=>{
this.initialized();
}, 1000);
}
initialized(){
console.log("Base initialized");
}
}
class Derived extends Base {
initialized(){
console.log("Derived initialized");
}
}
var test:Derived = new Derived(); // console logs "Derived initialized" - as expected.
Works well in the Playground (Ignore the odd red underline on setTimeout(), which I think is a bug - it compiles and runs fine.)
You do need the method present on Base, but you can override it in Derived (with or, as in this case, without a call to super.initialized()).
In order to do that you would need to have initialized as an abstract member of the abstract class. typescript currently does not support this however the feature has been asked for and there is a work item open for it:
http://typescript.codeplex.com/workitem/395

Categories

Resources