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

kx5bkwkv  于 2023-06-07  发布在  TypeScript
关注(0)|答案(3)|浏览(354)

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

lx0bsm1f

lx0bsm1f1#

在javascript中没有强制转换,所以你不能在“强制转换失败”时抛出。
Typescript支持强制转换,但这仅适用于编译时,您可以这样做:

const toDo = req.body as IToDoDto;
// or
const toDo = <IToDoDto> req.body; // deprecated

您可以在运行时检查该值是否有效,如果不是则抛出错误,即:

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所指出的,不需要类型Assert,因为isToDoDto是一个类型保护,所以这应该足够了:

if (!isToDoDto(req.body)) {
    throw new Error("invalid request");
}

this.toDoService.addToDo(req.body);
bmp9r5qi

bmp9r5qi2#

这里有另一种方法来强制类型转换,即使是在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进行验证。

pkwftd7m

pkwftd7m3#

如果它帮助任何人,我有一个问题,我想把一个对象作为另一种类型与类似的接口。我尝试了以下操作:

没有通过掉毛

const x = new Obj(a as b);

linter抱怨a缺少b上存在的属性。换句话说,a具有b的一些性质和方法,但不是全部。为了解决这个问题,我遵循了VS Code的建议:

通过掉毛测试

const x = new Obj(a as unknown as b);
  • 请注意,如果您的代码尝试调用类型b上存在的属性之一,而该属性未在类型a上实现,则应意识到运行时错误。*

相关问题