在TypeScript中将对象转换为接口

Eli*_*cia 59 casting interface object typescript

我正试图在我的代码中使用快速(使用正文解析器中间件)的请求正文进行接口,但它不起作用.有可能这样做吗?

这是我的界面:

export interface IToDoDto {
  description: string;
  status: boolean;
};
Run Code Online (Sandbox Code Playgroud)

这是我正在尝试进行演员的代码:

@Post()
addToDo(@Response() res, @Request() req) {
  const toDo: IToDoDto = <IToDoDto> req.body;
  this.toDoService.addToDo(toDo);
  return res.status(HttpStatus.CREATED).end();
}
Run Code Online (Sandbox Code Playgroud)

最后,被调用的服务方法:

public addToDo(toDo: IToDoDto): void {
  toDo.id = this.idCounter;
  this.todos.push(toDo);
  this.idCounter++;
}
Run Code Online (Sandbox Code Playgroud)

我可以通过任何论点,这将工作正常.我已经读过在TypeScript中不存在强制转换而是类型断言,所以它只会告诉编译器一个对象的类型为x,所以...我错了吗?这样做的方法是什么?谢谢.

Nit*_*mer 82

javascript中没有强制转换,因此如果"强制转换失败",则无法抛出.
Typescript 支持转换,但这仅适用于编译时,你可以这样做:

const toDo = <IToDoDto> req.body;
// or
const toDo = req.body as IToDoDto;
Run Code Online (Sandbox Code Playgroud)

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

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();
}
Run Code Online (Sandbox Code Playgroud)

编辑

正如@huyz指出的那样,不需要类型断言,因为它isToDoDto是一个类型保护,所以这应该足够了:

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

this.toDoService.addToDo(req.body);
Run Code Online (Sandbox Code Playgroud)

  • 对于通常正在寻找类型断言的任何人,请勿使用&lt;&gt;。不推荐使用。用```as``` (3认同)
  • “_javascript 中没有强制转换,因此如果“强制转换失败”则不能抛出异常。_”我认为,更重要的是,TypeScript 中的接口不可操作;事实上,它们是 100% [语法糖](https://en.wikipedia.org/wiki/Syntropic_sugar)。它们使维护结构更容易_概念上_,但是_对转译的代码没有实际影响_——在我看来,这是极其令人困惑/反模式的,正如OP的问题所证明的那样。没有理由不能将接口不匹配的东西扔进转译的 JavaScript 中;这是 TypeScript 有意识的(在我看来,也是很糟糕的)选择。 (2认同)

Jas*_*son 10

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

没有通过 linting

const x = new Obj(a as b);
Run Code Online (Sandbox Code Playgroud)

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

通过 linting 和测试

const x = new Obj(a as unknown as b);
Run Code Online (Sandbox Code Playgroud)

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

  • 我很高兴找到这个答案,但请注意,如果您通过网络或其他应用程序发送“x”,则可能会泄露个人信息(例如,如果“a”是用户),因为“x”仍然具有“a”的所有属性,只是它们不适用于打字稿。 (2认同)

Sep*_*ehr 5

这是强制TS编译器通常抱怨的不兼容类型和接口之间进行类型转换的另一种方法:

export function forceCast<T>(input: any): T {

  // ... do runtime checks here

  // @ts-ignore <-- forces TS compiler to compile this as-is
  return input;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用它强制将对象强制转换为特定类型:

import { forceCast } from './forceCast';

const randomObject: any = {};
const typedObject = forceCast<IToDoDto>(randomObject);
Run Code Online (Sandbox Code Playgroud)

请注意,为了减少复杂性,我省略了在转换之前应该进行运行时检查的部分。我在项目中所做的就是将所有.d.ts接口文件编译为JSON模式,并ajv用于在运行时进行验证。