web-dev-qa-db-fra.com

Objet Cast pour l'interface dans TypeScript

J'essaie de transtyper mon code à partir du corps d'une requête express (en utilisant un middleware body-parser) vers une interface, mais cela ne fonctionne pas. C'est possible de faire ça?

Ceci est mon interface:

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

C'est le code où j'essaye de faire le casting:

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

Et enfin, la méthode de service appelée:

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

Je peux passer n'importe quels arguments et cela fonctionnera bien. J'ai lu que, dans TypeScript, il n'y a pas de transtypage, mais une assertion de type, de sorte que le compilateur sera seulement informé qu'un objet est de type x, alors ... Ai-je tort? Et comment faire cela? Merci.

48
Elias Garcia

Il n'y a pas de casting en javascript, vous ne pouvez donc pas lancer si "le casting échoue".
TypeScript supporte le casting mais c'est seulement pour le temps de compilation, et vous pouvez le faire comme ceci:

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

Vous pouvez vérifier au moment de l'exécution si la valeur est valide et, le cas échéant, émettre une erreur, c'est-à-dire:

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();
}

Modifier

Comme @huyz l'a souligné, l'assertion de type n'est pas nécessaire car isToDoDto est un type guard, ce qui devrait suffire:

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

this.toDoService.addToDo(req.body);
70
Nitzan Tomer

Voici un autre moyen de forcer une transtypage de type même entre types et interfaces incompatibles lorsque le compilateur TS se plaint normalement:

export function forceCast<T>(input: any): T {

  // ... do runtime checks here

  // @ts-ignore <-- forces TS compiler to compile this as-is
  return input;
}

Vous pouvez ensuite l'utiliser pour forcer les objets convertis à un certain type:

import { forceCast } from './forceCast';

const randomObject: any = {};
const typedObject = forceCast<IToDoDto>(randomObject);

Notez que j'ai laissé de côté la partie que vous êtes supposé faire des vérifications d'exécution avant le casting afin de réduire la complexité. Ce que je fais dans mon projet est de compiler tous mes fichiers d'interface .d.ts dans des schémas JSON et d'utiliser ajv pour valider au moment de l'exécution.

5
Sepehr