Variable 'Foo' used before declaration. Two classes interdependence - angularjs

Please, help me solve the problem.
"no-use-before-declare" in tslint.json is true. And I am not allowed to change it.
The problem is following - "variable 'foo' used before declaration" build error.
The code may be simplified to:
export class One {
toSecond() : Two {
return new Two();
}
}
export class Two {
toFirst() : One {
return new One();
}
}
Could it be hacked somehow to overcome the linter warning and have the same result. Any workaround?

You could do:
let Two_forward: typeofTwo;
export class One {
toSecond() : Two {
return new Two_forward();
}
}
export class Two {
toFirst() : One {
return new One();
}
}
// Work around https://github.com/palantir/tslint/issues/3655
type typeofTwo = typeof Two;
Two_forward = Two;
but IMO this is unreasonable compared to just suppressing the lint error with // tslint:disable-next-line:no-use-before-declare. (And it might need further changes if the strictLocalInitialization option proposed here becomes part of strict.)

This was previously filed as a bug on tslint and the resolution was that classes are not hoisted and cannot be used before declaration. The rule is correct in this case.

Related

Cannot access enum before initialization, react typescript

In my program, I have lots of files with enum definitions like this and some files which join enums together. The enums are string-enums, so the indexing is not part of the problem. When I join enums together I get the error "Cannot access 'Both' before initialization". There are also circular imports, since I am using the combined enum in the first file. I understand the error message, however I import the files containing the necessary enums before defining 'Both'. Is this a typescript bug or am I missing something? I am using typescript in a React environment, so maybe I am missing the right tsconfig lines.
// firstFile.ts
export enum One
{
A,
B,
}
export enum Two
{
C = 2,
D,
}
// secondFile.ts, throws error
import { One, Two } from './firstFile';
export const Both =
{
...One,
...Two,
}
Circular dependencies are allowed in TypeScript (and ECMAScript as well), the static resolution of import and export clauses will work, but you have to be careful of the execution order of the files, depending on the entry point. Indeed, when a circular dependency is met, the entry point acts as the trunk of the dependency tree, so the other files execute before. When a file executes all of its top-level code executes, and will fail if it meets unresolved variables.
Now let's see what happens in your particular case. Your code transpiles to something like this:
firstFile.ts
import { Both } from "./secondFile.js";
export var One;
(function (One) {
One[One["A"] = 0] = "A";
One[One["B"] = 1] = "B";
})(One || (One = {}));
export var Two;
(function (Two) {
Two[Two["C"] = 2] = "C";
Two[Two["D"] = 3] = "D";
})(Two || (Two = {}));
secondFile.ts
import { One, Two } from './firstFile.js';
export const Both = Object.assign(Object.assign({}, One), Two);
If you use secondFile.ts as the entry point, firstFile.ts will execute first and will not throw any error because Both is unused in firstFile.ts.
However, if you add let's say a console.log(Both.A) at the end of firstFile.ts it will fail with a Cannot access 'Both' before initialization error because secondFile.ts has not executed yet, so Both is exported but not initialized.

How to access methods from array element?

I've recently taken upon myself to add setter and getter methods to my class.
Since doing this, many parts of my code got broken and I'm unable to access getter methods.
Take the example below:
private loadInputs() : Input[] {
var inputs = <Input[]>this.get('inputs');
inputs.sort((a,b) => a.QuoteRef().localeCompare(b.QuoteRef()))
return( inputs || [] );
}
My input class has 2 variables,
_Project: string
_line: string
Which I access using a method QuoteRef()
public QuoteRef(): string {
return this._Project.concat('-' + this._Line.toString().padStart(3,'0'));
}
Whenever I try to access a method or a getter from my class on an item that is casted as an Input, I can see the variables (though not access them as they are private), but the prototype section doesn't contain any of the methods.
This triggers the following error in the website console:
TypeError: a.QuoteRef is not a function
What am I doing wrong?
Update
I got it to work by updating the code as follows:
inputs.sort((a,b) => {
let first = new Input(a);
let second = new Input(b);
return first.QuoteRef().localeCompare(second.QuoteRef());
});
Without seeing your complete class I can only guess, but I think that a and b in your sort are not of the type you expect. I can't see what this.get('inputs') does, but I suspect it is not returning an array with Input class objects. Hence the function cannot be found (is not a function). You could try:
inputs.sort((a,b) => {
console.log(typeof a);
console.log(typeof b);
a.QuoteRef().localeCompare(b.QuoteRef());
})
and check what the type is. Then check what your this.get actually returns.
Edit: forgot to mention that your IDE probably does not warn you because you cast the output of this.get to <Input[]>.

Picking correct enum type to access object nested property

It is quite common case for me but yet I didn't stumble upon easy solution for this.
I have following enums (there are more values for each enum but for sake of simplicity I trimmed them down to two. Also note that same enum keys and values in every one of them is just a result of trimming and is not the specific case):
enum CampPersons {
HEALER = 'healer',
MERCHANT = 'merchant',
TUTOR = 'tutor',
}
enum HealerUpgrades {
UNLOCK = 'unlock',
TRAVEL = 'travel',
}
enum MerchantUpgrades {
UNLOCK = 'unlock',
TRAVEL = 'travel',
}
enum TutorUpgrades {
UNLOCK = 'unlock',
}
export type CampPersonUpgrades = HealerUpgrades | MerchantUpgrades | TutorUpgrades;
then I have object using those enums like this:
export const CampPersonUpgradesIcons = {
[CampPersons.HEALER]: {
[HealerUpgrades.UNLOCK]: HealIcon,
[HealerUpgrades.TRAVEL]: TravelIcon,
},
[CampPersons.MERCHANT]: {
[MerchantUpgrades.UNLOCK]: GoldIcon,
[MerchantUpgrades.TRAVEL]: TravelIcon,
},
[CampPersons.TUTOR]: {
[TutorUpgrades.UNLOCK]: BookIcon,
},
};
The problem arises when I try to access appropriate icon for person upgrade
const person: CampPersons = ...;
const upgrade: CampPersonUpgrades = ...;
const icon = CampPersonUpgradesIcons[person][upgrade];
Obviously typescript compiler can't determine if upgrade used to access specific icon is correct for CampPersonUpgradesIcons[person] because it can be either HealerUpgrades, MerchantUpgrades or TutorUpgrades.
Obviously for human (not typescript) when person is CampPersons.HEALER then upgrade would be from HealerUpgrades. My question is what is the easiest way to tell typescript compiler that upgrade for person will match appropriate enum (without using conditional typing like upgrade extends HealerUpgrades ? HealerUpgrades : ... or //#ts-ignore 😉).
Edit: I used #jcalz answer in my React component but unfortunately I've encountered further problems illustrated in this playground
As you note, you can't just say that person is of type CampPersons and that upgrade is of type CampPersonUpgrades and expect the compiler to understand how they are related. It's possible you might want the icon-indexing code to be generic in the type of person, like this:
function getIcon<P extends CampPersons>(
person: P, upgrade: keyof typeof CampPersonUpgradesIcons[P]) {
return CampPersonUpgradesIcons[person][upgrade]; // okay
}
Here person is now of generic type P which is constrained to CampPersons, and the type of upgrade is explicitly related to P. This gives you the following behavior:
const healerUnlockIcon = getIcon(CampPersons.HEALER, HealerUpgrades.UNLOCK); // okay
const oopsIcon = getIcon(CampPersons.MERCHANT, TutorUpgrades.UNLOCK); // error!
// ------------------------------------------> ~~~~~~~~~~~~~~~~~~~~
// 'TutorUpgrades' is not assignable to 'MerchantUpgrades'
Does that meet your needs or at least give you some direction? Good luck!
Playground Link to code

How to fix "expected call-signature to have a typedef" error

I have a switch case function inside my render JSX element that I am using in another const value based on the return values.
I tried looking for a solution to my issue online but none of the answers I found are helping my issue, even after trying them on my code.
function carouselClass(transitionTypeValue: any) {
switch(transitionTypeValue) {
//Different cases and their return values
}
}
const classes = xyz(carouselClass(transitionType)) //Sample of where I'm using my switch function
The code runs fine on Typescript side but I get a linting error which says "typedef expected call-signature: 'carouselClass' to have a typedef"
I tried my best to give enough context, please let me know if more is required as this is my first time posting a question.
Linter giving 'Missing Type definition' warning. Check this out-
https://github.com/palantir/tslint/blob/master/src/rules/typedefRule.ts for details.
Solution: You need to specify the return type for function explicitly
function carouselClass(transitionTypeValue: any):any {
switch(transitionTypeValue) {
//Different cases and their return values
}
}
I think you should add return type if you are calling function and returning something.
function carouselClass(transitionTypeValue: any):any {
switch(transitionTypeValue) {
//Different cases and their return values
}
}
const classes = xyz(carouselClass(transitionType))
You should avoid using type any where ever you can.
Avoid returning any or value with multiple types,
but if you still want to return multiple types of value, try to find similarity and create Enum type or Wrapper Interface, or you can try to create generic function.
interface IClassType extend IClassA, IClassB {}
function carouselClass(transitionTypeValue: any): IClassType {
switch(transitionTypeValue) {
// Different cases and their return values
// Avoid returning multiple types,
// but if you still want to return multiple types of value,
// try to find similarity and create Enum type or Wrapper Interface
}
}
const classes: xyz<IClassType> = xyz(carouselClass(transitionType))

Extjs 5 - static function call other static function from same class

I have code like this:
Ext.define( 'someClass', {
statics : {
methodA : function( ) { return 'A'; },
methodAB : function( ) {
var A = this.methodA();
return A + 'B';
}
}
} );
I have problem with accessing static methodA.
Can someone help me what would be a proper way to do it ?
you should call statics using the fully qualified className.methodName() syntax. 'this' inside a static is not going to be what you think it is. For example, if called from an event handler it will probably be the 'window' object, which certainly doesn't have a methodA() method. In other cases 'this' may be the prototype. In that case you may get away with this syntax but it is misleading and likely to cause future bugs.

Resources