将对象转换为 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
Cast object to interface in TypeScript
提问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 isToDoDto
is 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.ts
interface files into JSON schemas and using ajv
to 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 a
was missing properties that existed on b
. In other words, a
had 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 b
that is not implemented on type a
, you should realize a runtime fault.
请注意,如果您的代码尝试调用存在于 typeb
上但未在 type 上a
实现的属性之一,则您应该意识到运行时错误。