i was having a model class: of structure:
export default class Info {
empId: number;
name: string;
designation: string
constructor(data) {
this.empId = data.empId;
this.name = data.name;
this.designation = data.designation;
}
}
I have to change this class to an interface.
export default interface Info{
empId: number;
name: string;
designation: string
}
service class:
getInfo(): Promise<Array<Info>> {
return http
.get(this.ENDPOINTS.PRODUCTS, {
})
.then((response) => {
console.log("response", response)
return response.data.map((info) => new Info(info));
)
})
.catch((error) => {
throw error;
});
}
I am getting error in this line return response.data.map((info) => new Info(info)); stating 'Info' only refers to a type, but is being used as a value here. Can anyone help me with how to deal with the interface here and what will be the syntax. Can please anyone help me in understanding when to use Class and Interface in React app
Related
I'm creating mini orm in my pet-project. Trying to do models usable in IDE and compiler, but stuck with typing problems.
I have base model class:
import { db } from '../db/db';
export interface Criteria<T> {
field: Extract<keyof T, string>;
value: T[Extract<keyof T, string>];
comparison?: string;
}
export class BaseModel {
static _pk = 'id';
static _table: string = null;
constructor(params: object) {
for (const key in params) {
if (Object.prototype.hasOwnProperty.call(params, key)) {
const fn = `${key}Process`;
if (typeof this[fn] === 'function') {
this[fn](params[key]);
} else {
this[key] = params[key];
}
}
}
}
create<T extends typeof BaseModel>(this: T): Promise<InstanceType<T>> {
const params = this._getParams(); //TS2339: Property '_getParams' does not exist on type 'T'.
const thisTyped = this.constructor as T;
return db
.insertFromModel(thisTyped._table, params)
.then((id) => thisTyped.findOne([{ field: thisTyped._pk, value: id }])); //TS2322: Type 'string' is not assignable to type 'Extract<keyof InstanceType<T>, string>'.
}
static findOne<T extends typeof BaseModel>(this: T, criteria: Criteria<InstanceType<T>>[]): Promise<InstanceType<T>> {
return db.selectFromModel(this._table, criteria, true).then((row: object) => {
return new this(row) as InstanceType<T>;
});
}
_getParams() {
const params = {};
for (const key of Object.keys(this)) {
if (['id', '_table', '_pk'].includes(key)) {
continue;
} else {
params[key] = this[key];
}
}
return params;
}
}
And child class:
import { BaseModel } from './BaseModel';
export class User extends BaseModel {
static _table = 'users';
static _pk = 'id';
id: number;
email: string;
password: string;
// eslint-disable-next-line #typescript-eslint/no-useless-constructor
constructor(props: { id?: number; email: string; password: string }) {
super(props);
}
}
static method from base class works good, but after adding create method I'm getting error while compile... Errors described in comments in code.
One more error could be achieved with code:
new User({ email: 'test#test.com', password: '123123' }).create().then((user) => {//TS2684: The 'this' context of type 'User' is not assignable to method's 'this' of type 'typeof BaseModel'. Type 'User' is missing the following properties from type 'typeof BaseModel': prototype, _pk, _table, findOne, and 2 more
console.log(user);
});
Don't understand what I'm doing wrong, I do all in analogy with static method.
Also full code for experiments available here - https://github.com/kricha/ts_q
thanks.
I have a tree data whose interface is defined as below:
interface IData {
id: string;
label: string; .
value: string;
expanded: boolean;
condition?: boolean;
dataState: 'SUCCESS';
locked: boolean;
enabled: boolean;
parent: string;
children: IData[];
}
And I have a list of errors with the following interface :-
interface IErrors {
id: string;
success: boolean;
errors: Array<IError>;
}
I would like to iterate over these errors and apply 'dataState' to 'FAILED' if any error.id is found on the IData[] i.e. I would have to change the node's 'dataState' property to 'FAILURE' if the data id matches with that in the list of error id's.
I've written the following logic, but it's taking 2 seconds for it to execute ( check with console.time ).
public setFailedDataToStatusFailed(data:IData[],errorsList:IErrors[]){
data.forEach(data => {
errorsList.forEach(error => {
if(data){
if(data.id === error.id){
data.ruleState = 'FAILURE';
return;
} else if(data.children){
this.setFailedRulesToStatusFailed(data.children,errorsList);
}
}
});
});
}
Is there a way to optimize this logic better ?
Thanks!
data.map(d => {
if(errorsList.findIndex( err => err.id === d.id )){
data.ruleState = 'FAILURE';
return;
}
if(d.children){
this.setFailedRulesToStatusFailed(data.children,errorsList);
}
})
How to correctly get nested entity? In example, i make this query:
const houseId = 1;
const userId = 1;
const house = await this.houseRepository.findOne({
id: houseId,
}, {
where: {
project: {
user: {
id: userId,
}
}
},
relations: ['project', 'project.user']
});
As a result, house variable contain project entity, but project do not contain user. How to include user into project?
As i understand from the documentation, the user property in project entity was declared as lazy and if i want to get it, i should resolve it:
const user = await house.project.user;
console.log(user);
-> undefined
But resolving user give undefined in console, especially since it undefined before resolve.
House entity class:
#Entity('house')
export class HouseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#ManyToOne(type => ProjectEntity, { eager: true })
project: ProjectEntity;
}
Project entity class:
#Entity('project')
export class ProjectEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#ManyToOne(type => UserEntity, user => user.projects)
user: UserEntity;
}
User entity class:
#Entity('user')
export class UserEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
first_name: string;
#OneToMany(type => ProjectEntity, project => project.user)
projects: ProjectEntity[];
}
I'm trying to implement a generic function interface and I cannot make it work.
IToken.ts
export interface IToken {
token: string;
expires: number;
}
ITokenMapper.ts
export interface ITokenMapper {
<T>(apiResult: any): T;
}
tokenMapper.ts
import {ITokenMapper} from "./interfaces/ITokenMapper";
import {IToken} from "./interfaces/IToken";
export const tokenMapper: ITokenMapper = function <IToken>(apiResult: any): IToken {
if(apiResult.token && apiResult.expires) {
return {token: apiResult.token as string, expires: apiResult.expires as number}
}
throw new Error('Unable to parse token');
};
Here is a screenshot from tokenMapper.ts saying IToken import is unused but I should have a use for it:
Edit : Using Typescript 3.0.3
I believe you can accomplish your typing with a generic interface ITokenMapper<T>
interface IToken {
token: string;
expires: number;
}
interface ITokenMapper<T> {
(apiResult: T): T;
}
const tokenMapper: ITokenMapper<IToken> = function (apiResult) {
if(apiResult.token && apiResult.expires) {
return { token: apiResult.token as string, expires: apiResult.expires as number};
}
throw new Error('Unable to parse token');
};
From: https://www.typescriptlang.org/docs/handbook/generics.html#generic-types
So here is what I changed to make it work
ITokenMapper.ts -> IMapper.ts renamed and updated
export type IMapper<T> = (apiResult: any) => T;
tokenMapper.ts -> abpTokenMapper.ts renamed and updated
import { IMapper } from "../../utils/IMapper";
import { IToken } from "../interfaces/IToken";
export const abpTokenMapper: IMapper<IToken> = (apiResult: any) => {
if (apiResult.accessToken && apiResult.expireInSeconds) {
return { token: apiResult.accessToken as string, expires: apiResult.expireInSeconds as number }
}
throw new Error('Unable to parse token');
};
I'm relatively new to the Typescript world, and I'm just working on a test app to get my self used to it. So I have this weird (?) issue with type restriction 'not working'.
I have an array defined in a class like member field this:
listings: Array<ICryptListingItem> = [];
And the interface is:
export interface ICryptListingItem {
name: string;
something: number;
}
Why is the compiler fine with doing:
this.listings = listings.data.map((listing) => {
return {
name: listing.name
}
});
The objects returned from listings.data.map is not implementing the interface the array has as it's type? What am I not getting here?
Thanks in advance.
TypeScript does handle this automatically; your code sample is missing some information. For example:
export interface ICryptListingItem {
name: string;
something: number;
}
class MyThing {
listings: Array<ICryptListingItem> = [];
doSomething() {
const listings = {
data: [
{ name: "the keeper" },
{ name: "the seeker" }
]
};
// Error here, as expected
this.listings = listings.data.map((listing) => {
return {
name: listing.name
}
});
}
}
Probably the type of either listings or listings.data is any, so the result of the map call is also any; any is then always an allowed type to assign to this.listings.