I'm having trouble on validating nested object when I try to update a specific prop of a nested object e.g.:
import { Type } from 'class-transformer';
import { IsOptional, IsString, ValidateNested } from 'class-validator';
class Nested {
#IsString()
#IsOptional()
readonly propA: string;
#IsString()
#IsOptional()
readonly propB: string;
}
export class UpdateDto {
#IsOptional()
#Type(() => Nested)
#ValidateNested()
readonly nested: Nested;
}
If I try to pass a dotted key like { "nested.propA": "test" } I get the following error
{
"statusCode": 400,
"message": [
"property nested.propA should not exist"
],
"error": "Bad Request"
}
A simplest solution can be adding in the parent object the dotted keys eg:
class Nested {
#IsString()
#IsOptional()
readonly propA: string;
#IsString()
#IsOptional()
readonly propB: string;
}
export class UpdateDto {
#IsOptional()
#Type(() => Nested)
#ValidateNested()
readonly nested: Nested;
#IsString()
#IsOptional()
readonly 'nested.propA': string; <==== THIS
#IsString()
#IsOptional()
readonly 'nested.propB': string; <==== THIS
}
With that approach I can pass both the entire object and a single prop, but it seems really redundant to me.
Any other way to validate using a "dot" syntax? The db is mongo where the dot syntax can be used to updating a specific prop of a nested object.
Thanks.
Related
I am getting the following error trying to implement an interface.
Build:Type '{ code: string; name: string; gender: string; annualSalary: number; dateOfBirth: string; }[]' is not assignable to type 'IEmployee[]'.
Here is the interface
//file employee.ts
export interface IEmployee {
code: string;
name: string;
gender: string;
annualSalary: number;
dateOfBirth: string;
//method
computeMonthlySalary(annualSalary: number): number;
}
export class Employee implements IEmployee {
constructor(public code: string, public name: string, public gender: string,
public annualSalary: number, public dateOfBirth: string) {
}
computeMonthlySalary(annualSalary: number): number {
return annualSalary / 12;
}
}
I am trying to implement it in employeelist.component.ts
//file employeelist.component.ts
import { Component } from '#angular/core';
import { IEmployee } from './employee';
#Component({
selector: 'list-employee',
templateUrl: 'app/employee/employeelist.component.html',
styleUrls: ['app/employee/employeelist.component.css']
})
export class EmployeeListComponent {
employees: IEmployee[];
// employees: any[]; //this works fine
selectedEmployeeCountRadioButton: string = 'All';
//getting error on this.employees
constructor() {
this.employees ={code:'emp101',name:'Tom',gender:'Male',annualSalary:95500,dateOfBirth:'12/6/1981'}];
}
}
Please guide!
The object you declared does not have the computeMonthlySalary method
try this
import { IEmployee, Employee } from './employee';
//...
this.employees =[new Employee('emp101','Tom','Male',95500,'12/6/1981')];
I declare a model in ingredient.model.ts
export class Ingredient {
constructor(private name: string, public amount: number) {}
getName() { return this.name }
}
In ingredients.service.ts, if I get them in this way:
httpClient.get<Ingredient>(url).subscribe(
(igredient) => {
console.log(igredient.getName());
});
It gives errors in console, such as "no method getName in property igredient".
Also, whenever I try to declare a property type Category[] it fails, but Array seems working fine.
Edit:
I want to provide more info.
Given the Igredient model and the following JSON structure:
{
name: "Apple",
amount: "5",
created_at: "date",
}
The Igredient constructor isn't even invoked, therefore the GET payload won't be parsed.
You'll need to use a property, not a method. The returned object is really a json object, and there is no such thing as "getName()" method (despite your effort to add a type information). Try something like this:
export interface Ingredient {
strin: string,
amount: number,
created_at: string
}
httpClient.get<Ingredient>(url).subscribe(
(igredient) => {
console.log(igredient.amount);
});
EDIT: You need to provide a type information based on the expected json object. If the returned json object has attributes, strin, amount, and created_at, then you need to define a type that is compatible with the expected json object.
In angular 5, You can do this:
export interface Deserializable<T> {
deserialize(input: any): T;
}
export class Ingredient implments Deserializable<Ingredient>{
constructor(private name: string, public amount: number) {}
deserialize(input: any): Project {
Object.assign(this, input);
// do nested thing here -pop arrays of nested objects and create them
}
return this;
}
now in your service:
httpClient.get<Ingredient>(url).pipe(map(elem=>this.foo(elem)))
.subscribe((igredient) => {console.log(igredient.getName());
});
foo(ingredient:Ingrdient){
var i = new Ingridiant().desrialize(ingredient)
}
after the map you will have the Ingradient class, not the object.
Is it possible to use Class like a type in interface ? For example, I have a class Animal, can I use something like:
interface I {
object: Animal
}
I've got en error on this situation:
class A {
public static foo(text: string): string {
return text;
}
}
interface IA {
testProp: A;
otherProp: any;
}
class B {
constructor(prop: IA) {
console.log(prop.otherProp);
console.log(prop.testProp.foo('hello!'));
}
}
TS2339: Property 'foo' does not exist on type 'A'
You need to use typeof A:
class A {
public static foo(text: string): string {
return text;
}
}
interface IA {
testProp: typeof A;
otherProp: any;
}
class B {
constructor(prop: IA) {
console.log(prop.otherProp);
console.log(prop.testProp.foo('hello!'));
}
}
The problem in your code is that the foo method is static. Static can only be used on classes not object.
In your case:
A.foo("hello); //works
new A().foo("hello"); //doesn't work since it's an instance of A
I am new to typescript. I have defined some classes. I have used them as a type for the property of another class. e.g:
fileone.ts
export class A {
propertyOne: string;
propertyTwo: string;
}
Now i have another class B in another file:
filetwo.ts
import { A } from './fileone';
export class B {
myProperty: A;
mySecondProperty: string;
}
I have instantiated this class B in another file.
I have the following code:
myapp.ts
import { B } from './filetwo';
export class C {
let myObj: B = new B();
myObj.myProperty.propertyOne = 'hello';
myObj.myProperty.propertyTwo = 'world'';
console.log(myObj);
}
Now when i try to set the property of A through B, it say the following error:
Cannot set the property "propertyOne" of undefined
Can we not do this like in java? And please explain why i cannot do what i am doing right now. And what is the correct approach for this. Please do not just give me solution to my problem but also an explanation.
You have set the correct type of your myProperty member but this variable is not initialized by just declaring the type. So you are trying to set a property propertyOne on an undefined variable on your instance of B.
If you want to have it initialized correctly, you need to do this manually in your class B:
export class B {
myProperty: A;
constructor() {
this.myProperty = new A();
}
}
myObj.myProperty is type of A which is not defined yet, so you should initialize it
myObj.myProperty = new A();
then use it
It may seem out of scope, but I had the same issues except I was using VueJs also. So, to piggy back off of Andreas Jägle answer. This minor variation worked for me except I had to add super(); to my class constructor.
importmodule.ts
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
import { MyProfile } from '../../data';
interface CurrentUser {
name: string;
title: string;
groupName: string; }
#Component
export default class Profile extends Vue {
profile: MyProfile;
constructor() {
super();
this.profile = new MyProfile();
} }
data.ts
export interface IPro {
name: string;
title: string;
groupName: string;
}
export class MyProfile implements IPro {
name = "User";
title = "Title";
groupName = "Group";
}
Q) How do I use the following interface module in the service below?
If I've got the following model generated from c#:
declare module App.Core.Model {
interface Address extends App.Core.Model.BaseEntity {
addressLine1: string;
addressLine2: string;
addressLine3: string;
area: string;
countryCode: string;
name: string;
postcode: string;
town: string;
}
}
Service:
// these don't work, get "model.ts error is not a module"
import {Client} from '../interfaces/model';
import {AdminUser} from '../interfaces/model';
import {Building} from '../interfaces/model';
#Injectable()
export class AppService {
...
}
The files live at:
app/interfaces/model.ts
app/services/service.ts
You can do the following (dots have been replaced by underscore):
declare module App_Core_Model {
export interface Address extends App.Core.Model.BaseEntity {
addressLine1: string;
addressLine2: string;
addressLine3: string;
area: string;
countryCode: string;
name: string;
postcode: string;
town: string;
}
}
declare module "app_core_model" {
export = App_Core_Model;
}
Then the interfaces should be available when importing the "app_core_model" module, for instance:
import {Address} from 'app_core_model';
Also it appears that a module name cannot contain a dot because it breaks the import