I'm new in TypeScript.
I'm getting error when trying to instantiating the class.
Below is my sample code, actual code is different can't share.
module ABC {
export class A {
public execute<T>(action: string, data?: any, callerContext?: any): IAsyncResult<T> {
// CODE::
var requestMessage = new Common.ClientClasses.ClientRequestMessage(); **// **ERROR- "WinRTError: Class not registered"****
requestMessage.requestUri = actionRequest;
requestMessage.method = "POST";
requestMessage.body = data ? JSON.stringify(data, null, 2) : null;
Common.ClientClasses.ClientRequest.executeAsync(requestMessage)
.done((result: Common.ClientClasses.ClientResponeMessage) => {
// CODE:
}
// Code::
}
}
}
declare module Common.ClientClasses {
class ClientRequestMessage {
public requestUri: string;
public method: string;
public body: string;
}
class ClientResponeMessage {
public status: number;
public statusText: string;
public responseText: string;
}
class ClientRequest {
static executeAsync(clientRequestMessage: ClientRequestMessage): any;
}
}
I did some improvements, should work:
module ABC {
export class A {
public execute<T>(action: string, data?: any, callerContext?: any) {
var requestMessage = new Common.ClientClasses.ClientRequestMessage();
requestMessage.method = "POST";
requestMessage.body = data ? JSON.stringify(data, null, 2) : null;
Common.ClientClasses.ClientRequest.executeAsync(requestMessage)
}
}
}
module Common.ClientClasses {
export class ClientRequestMessage {
public requestUri: string;
public method: string;
public body: string;
}
class ClientResponeMessage {
public status: number;
public statusText: string;
public responseText: string;
}
export class ClientRequest {
static executeAsync(clientRequestMessage: ClientRequestMessage): any {
console.log("test");
}
}
}
Then it can be run as following:
var a = new ABC.A();
a.execute("some string");
declare module creates a definition file used for Intellisense but it doesn't provide any implementation that's why I changed your code so this fragment can work.
Also if you want to use any classes from the module, you must export them so they can be visible from outside of that module.
Related
I have two classes where I want to define a static Schema property using typebox. I also need to define a dependency between the two classes: first class schema must have an array of type of the second class schema:
import {Type, Static} from '#sinclair/typebox';
class ClassA {
static Schema = Type.Object({
id: Type.String(),
data: Type.Array(ClassB.Schema) // ERROR: <-- Property 'Schema' is used before its initialization.
})
constructor(id: string, data: ClassB[]) {
this.id = id;
this.data = data;
}
public id: string;
public data: ClassB[];
}
class ClassB {
static Schema = Type.Object({
id: Type.String(),
})
constructor(id: string) {
this.id = id;
}
public id: string;
}
Problem is I can't pass ClassB.Schema as argument for Type.Array(), I got the error: Property 'Schema' is used before its initialization. I thought that since both are static properties, they are evaluated at the same time but it doesn't seem the case. Any idea how to workaround this?
Well, it seems it is enough to invert the order of class declarations...
import {Type, Static} from '#sinclair/typebox';
class ClassB {
static Schema = Type.Object({
id: Type.String(),
})
constructor(id: string) {
this.id = id;
}
public id: string;
}
class ClassA {
static Schema = Type.Object({
id: Type.String(),
data: Type.Array(ClassB.Schema)
})
constructor(id: string, data: ClassB[]) {
this.id = id;
this.data = data;
}
public id: string;
public data: ClassB[];
}
I'm encountering the error
ContestDetailsModalComponent.html:21 ERROR TypeError: Cannot assign to read only property 'winner' of object '[object Object]'
at ContestDetailsModalComponent.onWinner (contest-details-modal.component.ts:88:24)
at Object.eval [as handleEvent] (ContestDetailsModalComponent.html:21:17)
at handleEvent (core.js:43993:77)
at callWithDebugContext (core.js:45632:1)
at Object.debugHandleEvent [as handleEvent] (core.js:45247:1)
at dispatchEvent (core.js:29804:1)
at core.js:42925:1
at HTMLButtonElement.<anonymous> (platform-browser.js:2668:1)
at ZoneDelegate.invokeTask (zone-evergreen.js:399:1)
at Object.onInvokeTask (core.js:39680:1)
when I try to make the assignment
this.contest.winner = winnerId;
you see in the following code snippet:
public onWinner(winnerId: number): void {
const post: Post = new Post();
post.title = `The winner of the contest has been elected: ${this.contest.title}`;
post.description = `Tizio has been elected winner of the contest and ${this.user.name} gives him the most welcome compliments`;
post.user = this.user;
post.contest = this.contest;
post.type = Type.WINNER;
post.level = Level.SUCCESS;
this.contest.winner = winnerId;
this.store.dispatch(PostActions.savePost({post}));
this.store.dispatch(ContestActions.saveContest({contest: this.contest}));
}
I've done this kind of assignment with other classes around the project and they never bothered me.
I enclose the contest class and post if it is useful:
export class Contest {
public id: number;
public title: string;
public description: string;
public rules: string;
public startDate: Date;
public endDate: Date;
public status: Status;
public winner: number;
public bannedUser: number[];
}
export class Post {
public id: number;
public title: string;
public description: string;
public level: Level;
public type: Type;
public user: User;
public publishDate: Date;
public contest: Contest;
}
I also tried some solutions always found on this forum such as:
Object.assign(target, source);
But he rightly tells me that this.contest.winner is null or undefined.
I hope for your help. Thank you
Edit:
This is the entire component.ts where onWinner() is present.
#Component({
selector: 'app-contest-details-modal',
templateUrl: './contest-details-modal.component.html',
styleUrls: ['./contest-details-modal.component.scss'],
})
export class ContestDetailsModalComponent implements OnInit, OnDestroy, AfterViewChecked {
private readonly subscriptions: Subscription = new Subscription();
public id: number;
public user: User;
public contest: Contest;
public images: Image[];
public hasVoted: boolean;
constructor(
private readonly bsModalRef: BsModalRef,
private readonly modalService: BsModalService,
private readonly store: Store<AppState>,
private cdRef: ChangeDetectorRef
) { }
public ngOnInit(): void {
this.subscriptions.add(this.store.pipe(select(AuthSelectors.getUser)).subscribe((user: User) => {
if (user) {
this.user = user;
}
}));
this.subscriptions.add(this.store.pipe(select(ContestSelectors.getById)).subscribe((contest: Contest) => {
if (contest) {
this.contest = contest;
}
}));
this.subscriptions.add(this.store.pipe(select(ImageSelectors.getImages)).subscribe((images: Image[]) => {
if (images.length) {
this.images = images;
}
}));
this.subscriptions.add(this.store.pipe(select(UserSelectors.check)).subscribe((ack: Ack) => {
if (ack) {
this.store.dispatch(AuthActions.updatedUser({userId: this.user.id}));
this.modalService.show(UploadImageModalComponent);
this.bsModalRef.hide();
}
}));
this.subscriptions.add(this.store.pipe(select(ImageSelectors.check)).subscribe((ack: Ack) => {
if (ack) {
this.bsModalRef.hide();
}
}));
}
public ngOnDestroy(): void {
this.store.dispatch(UserActions.clean());
this.store.dispatch(ContestActions.clean());
this.subscriptions.unsubscribe();
}
public onWinner(winnerId: number): void {
const post: Post = new Post();
post.title = `The winner of the contest has been elected: ${this.contest.title}`;
post.description = `Tizio has been elected winner of the contest and ${this.user.name} gives him the most welcome compliments`;
post.user = this.user;
post.contest = this.contest;
post.type = Type.WINNER;
post.level = Level.SUCCESS;
this.contest.winner = winnerId;
this.store.dispatch(PostActions.savePost({post}));
this.store.dispatch(ContestActions.saveContest({contest: this.contest}));
}
public onJoin(): void {
this.store.dispatch(UserActions.saveUser({idUser: this.user.id, id: this.contest.id}));
}
public onVote(image: Image): void {
let vote: number = image.vote;
vote = vote + 1;
this.store.dispatch(ImageActions.updateImage({photoId: image.id, votes: vote, userId: this.user.id}));
this.store.dispatch(AuthActions.updatedUser({userId: this.user.id}));
}
public isContain(contestId: number): boolean {
if (this.user.myContest) {
for (const i of this.user.myContest) {
if (contestId === i) {
return true;
}
}
}
return false;
}
public isImageVoted(id: number): boolean {
if (this.user.favouritePhoto) {
for (const imageVoted of this.user.favouritePhoto) {
if (id === imageVoted) {
this.hasVoted = true;
return true;
}
}
return false;
}
}
public onBan(image: Image): void {
this.modalService.show(BanModalComponent, {initialState : image});
this.bsModalRef.hide();
}
public isBan(contestId: number): boolean {
if (this.user.whereBanned) {
for (const contestBanned of this.user.whereBanned) {
if (contestId === contestBanned) {
return true;
}
}
return false;
}
}
public ngAfterViewChecked(): void {
this.cdRef.detectChanges();
}
}
contest contains a reference to an Observable emission, and all references emitted by Observables are readonly. Either clone contest:
this.contest = { ...contest };
Or, better, leave it as an Observable and consume it as such, generally via the async pipe. Also, if you're using NgRx, you want to be using store.select():
this.contest$ = this.store.select(ContestSelectors.getById);
How I can use getter and setter in TypeORM.
I saw issues in here and also here, but not found answer
For example a left my User entity
export class User {
#PrimaryGeneratedColumn()
private id: number;
#Column()
#Length(4, 20)
#IsNotEmpty()
private name: string;
#Column()
#Length(4, 100)
#IsNotEmpty()
private password: string;
public getId(): number {
return this.id;
}
public getPassword(password: string): string {
return this.password;
}
public setPassword(password: string): User {
this.password = bcrypt.hashSync(password, 8);
return this;
}
public setName(name: string): User {
this.name = name;
return this;
}
}
I use TypeORM version 0.2.7
#BeforeInsert & #AfterLoad
BeforeInsert https://typeorm.io/#/listeners-and-subscribers/beforeinsert
AfterLoad https://typeorm.io/#/listeners-and-subscribers/afterload
Use #BeforeInsert as setter
#Entity()
export class Post {
#BeforeInsert()
updateDates() {
this.createdDate = new Date()
}
}
Use #AfterLoad as getter
#Entity()
export class Post {
#AfterInsert()
resetCounters() {
this.counters = 0
}
}
I want to create a domain model correctly.
My attempt below creates the properties outside the constructor.
Should I be creating and setting the properties of the TestModel class inside the constructor only? this way their would be less lines of code
I have the below attempt that I think is correct:
export class TestModel1 {
public currentPage: number = 0;
public hasNext: boolean = false;
public hasPrev: boolean = false;
public pageSize: number = 0;
public totalItems: number = 0;
constructor(data: any) {
this.currentPage = data.currentPage;
this.hasNext = data.hasNext;
this.hasPrev = data.hasPrev;
this.pageSize = data.pageSize;
this.totalItems = data.totalItems;
}
}
It just seems a little big, too many lines of code.
Currently I need to pass in a data object and then map.
Is their a clever way for me to implement this better using the constructor function?
If we speak about the model class, the declaration of that should be like in example below:
export class Account {
constructor(
public activated: boolean,
public authorities: string[],
public email: string,
public firstName: string,
public langKey: string,
public lastName: string,
public login: string,
public imageUrl: string
) {}
}
Certainly you should not to define values outside of constructor. You may do declare the model class members as you have in your example, but without the definition of values:
export class TestModel1 {
public currentPage: number;
public hasNext: boolean;
public hasPrev: boolean;
public pageSize: number;
public totalItems: number;
constructor(data: any = null) {
if(data !== null) {
this.currentPage = data.currentPage;
this.hasNext = data.hasNext;
this.hasPrev = data.hasPrev;
this.pageSize = data.pageSize;
this.totalItems = data.totalItems;
}
}
}
And if you want to declare default values, my advice is to do this inside the constructor for clean and good code.
Update:
export class TestModel1 {
public currentPage: number;
public hasNext: boolean;
public hasPrev: boolean;
public pageSize: number;
public totalItems: number;
constructor(data: any = null) {
if(data !== null) {
this.currentPage = data.currentPage;
this.hasNext = data.hasNext;
this.hasPrev = data.hasPrev;
this.pageSize = data.pageSize;
this.totalItems = data.totalItems;
}
else {
this.currentPage = 0;
this.hasNext = false;
this.hasPrev = false;
this.pageSize = 0;
this.totalItems = 0;
}
}
}
That's would be better, if you want to have defaults
The main issue I see in the question is that of duplication. All of the properties are duplicated in the constructor, which violates the DRY principle of clean code.
If you want to populate a new instance of your domain object in a more concise way, you can do the following:
export class TestModel1 {
public currentPage: number;
public hasNext: boolean;
public hasPrev: boolean;
public pageSize: number;
public totalItems: number;
constructor(data: any) {
Object.keys(data).forEach(key => {
this[key] = data[key]
});
}
}
You have to ensure that the input data object will have the correct properties only, which may or may not be easy, based on the source of data.
I'm developping a NodeJS app with typescript. I've updated typescript to 2.4.1 and I have a "is not assignable to type" error with Generics class. I've read that the new version has improved checking for generics (https://blogs.msdn.microsoft.com/typescript/2017/06/27/announcing-typescript-2-4/). But I still can't see what's wrong with my code...
I have a factory :
export abstract class EntityClass {
public abstract getTable (): string
}
export class FactoryClass {
public getRepository<T extends EntityClass> (target): Repository<T> {
return new Repository<T>(target)
}
}
My Repository class :
export interface NxtDbColumnValuePair {
column: string
value: any
}
export class Db {
public insert (): Db {
return this
}
public setTable (table: string) {
return this
}
public setColumnsValuesPair (colValPairs: NxtDbColumnValuePair[]) {
return this
}
public execute (): Promise<any> {
return Promise.resolve({ inserId: 1 })
}
}
export class Repository<T extends EntityClass> {
private db: Db = new Db()
constructor (private entity) {}
public insert (entityInstance: T): Promise<T> {
const propertiesNameEntity = Object.getOwnPropertyNames(entityInstance)
const colValPairs: NxtDbColumnValuePair[] = propertiesNameEntity
.map((prop: string) => {
return {
column: prop,
value: entityInstance[prop],
}
})
return this.db.insert() // Insert value in SQL table
.setTable(entityInstance.getTable())
.setColumnsValuesPair(colValPairs)
.execute()
.then((results) => results.inserId) // Get new id inserted
.then((id) => this.find(id)) // get entity by id and return it
}
public find (id?: number): Promise<T> { // I didn't put the code for this method but this is the definition
return Promise.resolve(new this.entity())
}
}
And this is where the code doesn't work :
export class User {}
export class Client {}
export class Token extends EntityClass {
public user: User
public client: Client
public token: string
public getTable (): string {
return 'token'
}
}
export class MyClass {
public generateNewToken (user: User, client: Client): Promise<Token> {
const factory: FactoryClass = new FactoryClass()
const token: string = '123456789' // Generated randomly
const tokenClass: Token = new Token() // this class extends EntityClass
tokenClass.user = user
tokenClass.client = client
tokenClass.token = token
return factory.getRepository(Token).insert(tokenClass) // Error here !
}
}
And the error is : Type 'Promise< EntityClass >' is not assignable to type 'Promise< Token >'. It works with typescript 2.2.1.
Thank you