Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast object to interface in TypeScript

I'm trying to make a cast in my code from the body of a request in express (using body-parser middleware) to an interface, but it's not enforcing type safety.

This is my interface:

export interface IToDoDto {
  description: string;
  status: boolean;
};

This is the code where I'm trying to do the cast:

@Post()
addToDo(@Response() res, @Request() req) {
  const toDo: IToDoDto = <IToDoDto> req.body; // <<< cast here
  this.toDoService.addToDo(toDo);
  return res.status(HttpStatus.CREATED).end();
}

And finally, the service method that's being called:

public addToDo(toDo: IToDoDto): void {
  toDo.id = this.idCounter;
  this.todos.push(toDo);
  this.idCounter++;
}

I can pass whatever arguments, even ones that don't come close to matching the interface definition, and this code will work fine. I would expect, if the cast from response body to interface is not possible, that an exception would be thrown at runtime like Java or C#.

I have read that in TypeScript casting doesn't exist, only Type Assertion, so it will only tell the compiler that an object is of type x, so... Am I wrong? What's the right way to enforce and ensure type safety?

like image 942
Elias Garcia Avatar asked Oct 12 '22 05:10

Elias Garcia


People also ask

How do I cast objects in TypeScript?

If we want to cast the object to string data types by using toString() method we can change the object type to a string data type. We can also cast the object type to jsonby using json. parse() method we can get only the plain objects and it not used on the class object.

Can you cast in TypeScript?

JavaScript doesn't have a concept of type casting because variables have dynamic types. However, every variable in TypeScript has a type. Type castings allow you to convert a variable from one type to another. In TypeScript, you can use the as keyword or <> operator for type castings.

Can we create object of interface in TypeScript?

To create an object based on an interface, declare the object's type to be the interface, e.g. const obj1: Employee = {} . The object has to conform to the property names and the type of the values in the interface, otherwise the type checker throws an error.


1 Answers

There's no casting in javascript, so you cannot throw if "casting fails".
Typescript supports casting but that's only for compilation time, and you can do it like this:

const toDo = <IToDoDto> req.body;
// or
const toDo = req.body as IToDoDto;

You can check at runtime if the value is valid and if not throw an error, i.e.:

function isToDoDto(obj: any): obj is IToDoDto {
    return typeof obj.description === "string" && typeof obj.status === "boolean";
}

@Post()
addToDo(@Response() res, @Request() req) {
    if (!isToDoDto(req.body)) {
        throw new Error("invalid request");
    }

    const toDo = req.body as IToDoDto;
    this.toDoService.addToDo(toDo);
    return res.status(HttpStatus.CREATED).end();
}

Edit

As @huyz pointed out, there's no need for the type assertion because isToDoDto is a type guard, so this should be enough:

if (!isToDoDto(req.body)) {
    throw new Error("invalid request");
}

this.toDoService.addToDo(req.body);
like image 219
Nitzan Tomer Avatar answered Oct 13 '22 18:10

Nitzan Tomer