我正在尝试在我的代码中从 express 中的请求主体(使用主体解析器中间件)到接口进行强制转换,但这并没有强制执行类型安全。
这是我的界面:
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强制转换不存在,只有类型断言,所以它只会告诉编译器一个对象是x
类型,所以......我错了吗?执行和确保类型安全的正确方法是什么?
javascript 中没有强制转换,因此如果“强制转换失败”,您将无法抛出。
Typescript supports casting 但这仅用于编译时间,您可以这样做:
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);
这是另一种强制类型转换的方法,即使在 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
在运行时进行验证。
如果它对任何人都有帮助,那么我遇到了一个问题,我想将一个对象视为具有类似界面的另一种类型。我尝试了以下操作:
没有通过 linting
const x = new Obj(a as b);
linter 抱怨 a
缺少 b
上存在的属性。换句话说,a
具有 b
的一些属性和方法,但不是全部。为了解决这个问题,我遵循了 VS Code 的建议:
通过 linting 和测试
const x = new Obj(a as unknown as b);
请注意,如果您的代码尝试调用类型 b
上存在但类型 a
上未实现的属性之一,您应该意识到运行时错误。
const toDo = req.body as IToDoDto;
中进行强制转换,因为 TS 编译器此时知道它是IToDoDto
as
any
还不能保证是IToDoDto
!”,但 TS 选择不这样做。如果编译器只捕获 some 类型冲突,在转译的代码中没有(你是对的;我应该在原版中更清楚@那个),不幸的是,imo,[主要是?] 糖。