将对象转换为 TypeScript 中的接口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43894565/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:43:51  来源:igfitidea点击:

Cast object to interface in TypeScript

objecttypescriptinterfacecasting

提问by Elias Garcia

I'm trying to make a cast in my code from the body of a request in express (using body-parser middleware) to an interface, but it's not enforcing type safety.

我正在尝试将我的代码从 express 中的请求正文(使用正文解析器中间件)转换为接口,但它没有强制执行类型安全。

This is my interface:

这是我的界面:

export interface IToDoDto {
  description: string;
  status: boolean;
};

This is the code where I'm trying to do the cast:

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

@Post()
addToDo(@Response() res, @Request() req) {
  const toDo: IToDoDto = <IToDoDto> req.body; // <<< cast here
  this.toDoService.addToDo(toDo);
  return res.status(HttpStatus.CREATED).end();
}

And finally, the service method that's being called:

最后,正在调用的服务方法:

public addToDo(toDo: IToDoDto): void {
  toDo.id = this.idCounter;
  this.todos.push(toDo);
  this.idCounter++;
}

I can pass whatever arguments, even ones that don't come close to matching the interface definition, and this code will work fine.I would expect, if the cast from response body to interface is not possible, that an exception would be thrown at runtime like Java or C#.

我可以传递任何参数,即使是那些与接口定义不匹配的参数,这段代码也能正常工作。我希望,如果从响应主体到接口的转换是不可能的,那么在运行时会像 Java 或 C# 一样抛出异常。

I have read that in TypeScript casting doesn't exist, only Type Assertion, so it will only tell the compiler that an object is of type x, so... Am I wrong? What's the right way to enforce and ensure type safety?

我读过 TypeScript 中的强制转换不存在,只有类型断言,所以它只会告诉编译器一个对象是 type x,所以......我错了吗?强制执行和确保类型安全的正确方法是什么?

回答by Nitzan Tomer

There's no casting in javascript, so you cannot throw if "casting fails".
Typescript supports castingbut that's only for compilation time, and you can do it like this:

javascript 中没有强制转换,因此如果“强制转换失败”,您将无法抛出。
Typescript支持强制转换,但这仅适用于编译时间,您可以这样做:

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

You can check at runtime if the value is valid and if not throw an error, i.e.:

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

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();
}


Edit

编辑

As @huyz pointed out, there's no need for the type assertion because isToDoDtois a type guard, so this should be enough:

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

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

this.toDoService.addToDo(req.body);

回答by Sepehr

Here's another way to force a type-cast even between incompatible types and interfaces where TS compiler normally complains:

这是另一种强制类型转换的方法,即使在 TS 编译器通常会抱怨的不兼容类型和接口之间也是如此:

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

  // ... do runtime checks here

  // @ts-ignore <-- forces TS compiler to compile this as-is
  return input;
}

Then you can use it to force cast objects to a certain type:

然后您可以使用它强制将对象强制转换为某种类型:

import { forceCast } from './forceCast';

const randomObject: any = {};
const typedObject = forceCast<IToDoDto>(randomObject);

Note that I left out the part you are supposed to do runtime checks before casting for the sake of reducing complexity. What I do in my project is compiling all my .d.tsinterface files into JSON schemas and using ajvto validate in runtime.

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

回答by Jason

If it helps anyone, I was having an issue where I wanted to treat an object as another type with a similar interface. I attempted the following:

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

Didn't pass linting

没有通过 linting

const x = new Obj(a as b);

The linter was complaining that awas missing properties that existed on b. In other words, ahad some properties and methods of b, but not all. To work around this, I followed VS Code's suggestion:

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

Passed linting and testing

通过 linting 和测试

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

Note that if your code attempts to call one of the properties that exists on type bthat is not implemented on type a, you should realize a runtime fault.

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