Ich versuche, meinen Code vom Text einer Anfrage in Express (mithilfe der Body-Parser-Middleware) in eine Schnittstelle umzuwandeln, erzwingt jedoch keine Typensicherheit.
Dies ist meine Schnittstelle:
export interface IToDoDto {
description: string;
status: boolean;
};
Dies ist der Code, in dem ich versuche, die Besetzung zu machen:
@Post()
addToDo(@Response() res, @Request() req) {
const toDo: IToDoDto = <IToDoDto> req.body; // <<< cast here
this.toDoService.addToDo(toDo);
return res.status(HttpStatus.CREATED).end();
}
Und schließlich die Servicemethode, die aufgerufen wird:
public addToDo(toDo: IToDoDto): void {
toDo.id = this.idCounter;
this.todos.push(toDo);
this.idCounter++;
}
Ich kann alle Argumente übergeben, auch solche, die nicht annähernd mit der Schnittstellendefinition übereinstimmen , und dieser Code funktioniert einwandfrei. Ich würde erwarten, dass zur Laufzeit eine Ausnahme wie Java oder C # ausgelöst wird, wenn die Umwandlung vom Antworttext in die Schnittstelle nicht möglich ist.
Ich habe gelesen, dass in TypeScript kein Casting vorhanden ist, sondern nur Type Assertion. Daher wird dem Compiler nur mitgeteilt, dass ein Objekt vom Typ x
ist. Also ... irre ich mich? Was ist der richtige Weg, um die Typensicherheit durchzusetzen und zu gewährleisten?
quelle
Antworten:
Es gibt kein Casting in Javascript, daher können Sie nicht werfen, wenn "Casting fehlschlägt".
Typescript unterstützt das Casting, dies gilt jedoch nur für die Kompilierungszeit. Sie können dies folgendermaßen tun:
const toDo = <IToDoDto> req.body; // or const toDo = req.body as IToDoDto;
Sie können zur Laufzeit überprüfen, ob der Wert gültig ist, und wenn nicht, einen Fehler auslösen, dh:
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(); }
Bearbeiten
Wie @huyz hervorhob, ist die Typzusicherung nicht erforderlich, da
isToDoDto
es sich um einen Typschutz handelt. Dies sollte also ausreichen:if (!isToDoDto(req.body)) { throw new Error("invalid request"); } this.toDoService.addToDo(req.body);
quelle
const toDo = req.body as IToDoDto;
da der TS-Compiler weiß, dass esIToDoDto
zu diesem Zeitpunkt ein istas
any
ist noch nicht garantiertIToDoDto
!", Aber TS hat sich dagegen entschieden. Wenn der Compiler nur fängt einige Typ Konflikte, und keiner in der transpiled Code (und Sie haben Recht, ich sollte mehr klar @ gewesen bin , dass im Original), Schnittstellen leider sind, imo, [meistens?] Zucker.Hier ist eine andere Möglichkeit, eine Typumwandlung auch zwischen inkompatiblen Typen und Schnittstellen zu erzwingen, bei denen sich der TS-Compiler normalerweise beschwert:
export function forceCast<T>(input: any): T { // ... do runtime checks here // @ts-ignore <-- forces TS compiler to compile this as-is return input; }
Dann können Sie es verwenden, um gegossene Objekte auf einen bestimmten Typ zu zwingen:
import { forceCast } from './forceCast'; const randomObject: any = {}; const typedObject = forceCast<IToDoDto>(randomObject);
Beachten Sie, dass ich den Teil, den Sie zur Laufzeitprüfung durchführen sollen, vor dem Casting weggelassen habe, um die Komplexität zu verringern. In meinem Projekt kompiliere ich alle meine
.d.ts
Schnittstellendateien in JSON-Schemas und überprüfe sieajv
zur Laufzeit.quelle
Wenn es jemandem hilft, hatte ich ein Problem, bei dem ich ein Objekt als einen anderen Typ mit einer ähnlichen Schnittstelle behandeln wollte. Ich habe Folgendes versucht:
Fusseln nicht bestanden
const x = new Obj(a as b);
Der Linter beschwerte sich, dass
a
Eigenschaften fehlten, die auf existiertenb
. Mit anderen Worten,a
hatte einige Eigenschaften und Methodenb
, aber nicht alle. Um dies zu umgehen, folgte ich dem Vorschlag von VS Code:Flusen und Testen bestanden
const x = new Obj(a as unknown as b);
Beachten Sie, dass Sie einen Laufzeitfehler feststellen sollten , wenn Ihr Code versucht, eine der Eigenschaften aufzurufen, die für einen Typ vorhanden sind, der für einen Typ
b
nicht implementiert ista
.quelle
get
undset
Methoden.