Объект Cast для интерфейса в 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 не существует casting, но Type Assertion, поэтому он будет сообщать компилятору, что объект имеет тип x, поэтому... Я ошибаюсь? И как это сделать? Благодарю.
Ответы
Ответ 1
В 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);
Ответ 2
Здесь еще один способ заставить тип-лить даже между несовместимыми типами и интерфейсами, где обычно компилятор 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
интерфейса .d.ts
в JSON-схемах и использует ajv
для проверки во время выполнения.
Ответ 3
Если это кому-нибудь поможет, у меня возникла проблема, когда я хотел рассматривать объект как другой тип с похожим интерфейсом. Я попытался сделать следующее:
Не прошло линтинга
const x = new Obj(a as b);
Линтер жаловался, что a
не хватает свойств, которые существовали на b
. Другими словами, a
имел некоторые свойства и методы b
, но не все. Чтобы обойти это, я следовал предложению VS Code:
Прошёл ворс и тестирование
const x = new Obj(a as unknown as b);
Обратите внимание, что если ваш код пытается вызвать одно из свойств, существующих в типе b
, которые не реализованы в типе a
, вы должны осознать ошибку времени выполнения.