在 TypeScript 中将对象强制转换为接口

我试图在我的代码中从 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 中不存在类型转换,只有类型断言,所以它只会告诉编译器一个对象是 x类型,所以... 我错了吗?什么是执行和确保类型安全的正确方法?

250436 次浏览

Javascript 中没有强制转换,所以如果“强制转换失败”,就不能抛出。
类型脚本 支撑铸造,但这只是为了编译时,你可以这样做:

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进行验证。

如果这对任何人有帮助的话,我遇到了一个问题,我想把一个对象当作另一种具有类似接口的类型来对待。我尝试了以下方法:

没通过筛选

const x = new Obj(a as b);

这个短程序抱怨 a缺少 b上存在的属性。换句话说,ab的一些性质和方法,但不是全部。为了解决这个问题,我采纳了 VS Code 的建议:

通过了起绒和测试

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

请注意,如果您的代码试图调用类型 b上存在但类型 a上没有实现的属性之一,则应该实现运行时错误。