I have an JSON Object received from an api call and the Object will have multiple values but all of type string. How to I write an Interface for such an Object in the shortest way.
I mean I can write and Interface with 100 keys whose type is string. But is there a more efficient way of doing this?
you can use Record(a utility type in typescript):
const info: Record<string, string> = {
name: "Bruce Wayne",
address: "Bat Cave"
};
you can use it in your service like this:
class MyService {
constructor(private readonly http: HttpClient) {}
callApi() {
return this.http.get<Record<string, string>>(url);
}
}
Related
I have two interfaces defined like this:
export interface PostView{
postName: string;
postTime: Time;
message: string | null;
replies: { [P in AccountType]?: Reply[][] };
}
export interface Post{
postName: string;
postTime: Time;
message: string | null;
replies: { [P in AccountType]?: Reply[] };
}
You can see that both the interface definitions are same except for the replies field.
Now, in a .tsx file, I'm getting an object of PostView. I want to call another function which requires Post object.
Also, for the replies field, I have to sent empty object to the function.
This is how I have currently.
const postViewObject: any = props.myPostView;
postViewObject.replies= {};
const request: Post = postViewObject;
functionToBeCalled(request);
You can see that I'm assigning PostView object to a variable of type any which I don't want to do. And then I'm updating replies field to empty object and casting it to Post object.
Is there a better way to write this code?
You could create a new post object using the spread operator:
const request: Post = {
...props.myPostView,
replies: {}
}
I find myself trying to use decorators with the native javascript private properties (#) and these first 'recognize' that are in use do not work.
I identified this by using the class-validator decorators on the private properties of my value objects.
The error I get in my code editor is: Decorators are not valid here
Example:
import { IsString } from 'class-validator';
Class Person {
#IsString()
#name: string;
constructor(name: string) {
this.#name = name;
}
get name(): string {
return this.#name;
}
}
Okey as suggested by VLAZ:
Private fields in JS are completely private and inaccessible to anything from outside. Thus it makes sense they cannot be decorated - there is no way for the decorator to access them.
This is completely correct, so when I took a closer look at the value object I realized that it does have public get properties, so by testing it is possible to use decorators on those properties.
Leaving something like:
import { IsString } from 'class-validator';
Class Person {
#name: string;
constructor(name: string) {
this.#name = name;
}
#IsString()
get name(): string {
return this.#name;
}
}
I am trying to combine multiple Parameter Decorator for my application.
In my application there are several custom decorators.
My Sample Controller.
#Controller('api')
export class MyController {
#Get('mainresponse')
public getResponse(
#Query() query: Partial<IBean>,
#Headers('user-agent') userAgent: string,
#MyFirstDocrator() firstDecorator: string,
#MySecondDocrator() secondDecorator: string,
#Headers('Referer') referer: string,
#Cookies('session') sessionId?: string,
): Observable<IResponse> {
......
}
}
I am trying to combine these decorators into 1 and return an object with all the decorators value.
Something like this
#Get('mainresponse')
public getResponse(
#MyCombinedDecorator() decorator: any
): Observable<IResponse> {
......
}
But when I am using applyDecorators it is giving me the return value of the last passed decorator.
export const MyCombinedDecorator = () => applyDecorators(Headers('user-agent') as PropertyDecorator, MyFirstDocrator() as PropertyDecorator, Query() as PropertyDecorator);
I have a class that has two methods for generating and decoding jsonwebtokens. This is what the class looks like.
interface IVerified {
id: string
email?: string
data?: any
}
export default class TokenProvider implements ITokenProvider {
public async generateToken({ id, email }: ITokenDetails): Promise<string> {
return sign({ id, email }, CONFIG.JWT.secret, {
subject: id,
expiresIn: CONFIG.JWT.expires,
})
}
public async decodeToken(token: string): Promise<IVerified> {
const user = verify(token, CONFIG.JWT.secret)
return user as IVerified
}
}
In the decodeToken method, as you can see from above, it takes in a token and is meant to return the decoded values embedded in the token. But vscode Intellisense shows that jwt.verify() method returns a string | object. How can I override this to enforce the method to return some user attributes? Instead of getting string | object, I want to return the attributes described by the IVerified interface stated above. Any help is appreciated! Thank you very much.
You generally have two options:
Coerce the result to a IVerified like you do there (you might have to do return (user as any) as IVerified; though to get typescript to do what you want. This is fine as long as you can guarantee that the object returned from jwt.verify adheres to the IVerified interface.
Create a helper function that takes in a string | object and does the necessary logic to do runtime validation, deserialization, etc, in order to ensure you get an IVerified back:
private function validateDecodedToken(input: string | object): IVerified {
// ... do whatever you need to parse/deserialize/validate/etc here
}
public async decodeToken(token: string): Promise<IVerified> {
const user = verify(token, CONFIG.JWT.secret);
return this.validateDecodedToken(user);
}
This is the more "robust" approach, but might be overkill if there
are other guarantees in the system.
I'm new to Angular & TypeScript and trying to figure out how to instantiate an object (before an api request is returned with the real data).
For example, my model looks like this:
//order.model.ts
export class Order {
constructor(public id: number, currency: string, public contact: Object, public items: Array<Object>) {}
}
And then I try to instantiate that in one of my components, let's say the App component:
//app.component.ts
export class AppComponent {
#Input()
public order: Order = new Order();
}
Of course, it expected to receive 4 arguments when instantiating new Order() but received 0. Do I actually have to pass in undefined/empty values for each attribute of Order?
In good ol' React (without TS) I would just initialize with an empty object and call it a day:
this.state = {
order: {}
}
What's best practice for this sort of thing in Angular/TS?
Yes as it is currently set up you would have to pass 4 default arguments to the constructor.
public order: Order = new Order(1, '', {}, []);
Or you can set each property as nullable by adding a ? like so:
export class Order {
constructor(public id?: number, currency?: string, public contact?: Object, public items?: Array<Object>) {}
}
If the class doesn't have functionality (you are simply using it for type checking) the best way to do it would be to declare an interface like so (you can also make them nullable here with ?s):
export interface Order {
id: number;
currency: string;
contact: Object;
items: Object[];
}
then in your component do not initialize the value until you have all of the needed values:
//app.component.ts
export class AppComponent {
#Input()
public order: Order;
// just an example
setValues(id: number, currency: string, contact: Object, items: Object[]) {
this.order = {
id: id,
currency: currency,
contact: contact,
items: items
}
}
// example for if you receive object with correct fields from backend
getData() {
this.service.getData().subscribe(result => {
this.order = result;
});
}
}