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


101

Expressのリクエストの本文(body-parserミドルウェアを使用)からインターフェイスにコードをキャストしようとしていますが、型の安全性を強制していません。

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

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

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

@Post()
addToDo(@Response() res, @Request() req) {
  const toDo: IToDoDto = <IToDoDto> req.body; // <<< cast here
  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++;
}

インターフェイス定義との一致に近づかない引数も含めて、どのような引数で渡すことができ、このコードは正常に機能します。応答本文からインターフェイスへのキャストが不可能な場合、JavaやC#のように実行時に例外がスローされると思います。

TypeScriptキャストには存在せず、Type Assertionのみが存在することを読みました。そのため、オブジェクトが型xであることがコンパイラに通知されるだけなので、...間違っていますか?型安全性を実施および確保するための正しい方法は何ですか?


1
「機能していません」と定義してください。正確に。エラーはありますか?どれ?コンパイル時に?実行時に?何が起こるのですか?
JB Nizet 2017年

1
実行時に、渡したオブジェクトを使用して、コードは正常に実行されます。
エリアスガルシア

あなたが何を求めているのかはっきりしていません
Nitzan Tomer 2017年

私の質問は、入力オブジェクトを型付きオブジェクトにキャストする方法です。キャストが不可能な場合は、...のJava、C#のように、実行時に例外をスロー
エリアス・ガルシア

これはあなたの質問に答えますか?TypeScriptまたはJavaScript型キャスト
MichaelFreidgeim20年

回答:


143

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

const toDo = req.body as IToDoDto;TSコンパイラはIToDoDtoこの時点でキャストインが必要であることを知っているので、キャストインは必要ないと思います
huyz 2018

10
一般に型アサーションを探している人は、<>を使用しないでください。これは非推奨です。使用as
AbhishekDeb19年

javascriptにはキャストがないので、「キャストが失敗した」場合はスローできません。」もっと重要なことは、TypeScriptのインターフェイスは実用的ではないと思います。実際、それらは100%シンタティックシュガーです。彼らはそれが簡単な構造を維持するために作る、概念的に、しかしtranspiledコードには実際の影響がありません-めちゃくちゃ混乱/アンチパターン、OPの質問証拠として、芋、です。インターフェイスと一致しないものがトランスパイルされたJavaScriptでスローできなかった理由はありません。TypeScriptによる意識的な(そして貧弱な、imo)選択です。
ラフィン

@ruffinインターフェースはシンタックスシュガーではありませんが、実行時のみに保持するという意識的な選択を行いました。実行時にパフォーマンスが低下することはないので、これは素晴らしい選択だと思います。
NitzanTomer20年

Tomayto tomahto?TypeScriptのインターフェイスからの型安全性は、トランスパイルされたコードには拡張されません。また、実行前でも型安全性は厳しく制限されますこれは、型安全性がまったくないOPの問題に見られます。TSは「ねえ、待って、あなたanyはまだ保証されてIToDoDtoいません!」と言うことができましたが、TSはそうしないことを選択しました。コンパイラが一部の型の競合のみをキャッチし、トランスパイルされたコードには何もキャッチしない場合(そして、その通りです。元のコードよりも明確にすべきでした)、残念ながら、インターフェイスはimo、[ほとんど?]砂糖です。
ラフィン

7

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実行時に検証するために使用することです。


2

それが誰かを助けるなら、私はオブジェクトを同様のインターフェースを持つ別のタイプとして扱いたいという問題を抱えていました。私は次のことを試みました:

リンティングに合格しませんでした

const x = new Obj(a as b);

リンターはa、に存在するプロパティが欠落していると不平を言っていましたb。言い換えれば、のaいくつかのプロパティとメソッドがbありましたが、すべてではありませんでした。これを回避するために、私はVSCodeの提案に従いました。

リンティングとテストに合格

const x = new Obj(a as unknown as b);

コードが、型にb実装されていない型に存在するプロパティの1つを呼び出そうとするとa、実行時の障害が発生することに注意してください。


1
この回答を見つけてよかったですが、「x」をネットワーク経由または別のアプリに送信している場合、「x」がまだユーザーであるため、個人情報が漏洩している可能性があることに注意してください'a'のすべてのプロパティがあり、typescriptでは使用できません。
ゾルタンMatók

@ZoltánMatókの良い点。また、シリアル化されたオブジェクトをネットワーク経由で送信することに関しては、JavaScriptとメソッドを介したJavaスタイルのゲッターとセッターについての議論getありsetます。
ジェイソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.