web-dev-qa-db-ja.com

TypeScriptのインターフェイスにオブジェクトをキャストします

私はコードで、エクスプレス(ボディパーサーミドルウェアを使用)のリクエストの本文からインターフェイスにキャストしようとしていますが、機能していません。これは可能ですか?

これは私のインターフェースです:

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

これは私がキャストしようとしているコードです:

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

そして最後に、呼び出されているサービスメソッド:

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

私はどんな引数でも渡すことができ、これはうまく機能します。 TypeScriptではキャストではなくタイプアサーションが存在することを読んだので、オブジェクトがタイプxであることをコンパイラに伝えるだけです...間違っていますか?そして、これを行う方法は何ですか?ありがとう。

48
Elias Garcia

Javascriptにはキャストがないため、「キャストが失敗した」場合はスローできません。
TypeScript キャストをサポート ただし、これはコンパイル時のみであり、次のように実行できます。

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

値が有効であり、エラーをスローしない場合は、実行時に確認できます。

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

編集

@huyzが指摘したように、isToDoDtoはタイプガードなので、タイプアサーションは必要ありません。これで十分です。

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

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

互換性のない型と、TSコンパイラが通常文句を言うインターフェース間でも型キャストを強制する別の方法を次に示します。

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

  // ... do runtime checks here

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

次に、それを使用して、オブジェクトを特定のタイプに強制的にキャストできます。

import { forceCast } from './forceCast';

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

複雑さを軽減するために、キャストする前にランタイムチェックを行うことになっている部分は省略したことに注意してください。私のプロジェクトで行うことは、すべての.d.tsインターフェイスファイルをJSONスキーマにコンパイルし、ajvを使用して実行時に検証することです。

5
Sepehr