ChatGPT解决这个技术问题 Extra ChatGPT

将对象转换为 TypeScript 中的接口

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

请定义“它不起作用”。要精确。有错误吗?哪一个?在编译时?在运行时?怎么了?
在运行时,无论我传递什么对象,代码都会正常执行。
不清楚你在问什么
我的问题是如何将传入对象转换为类型化对象。如果无法进行强制转换,请在运行时抛出异常,如 Java、C#...
这回答了你的问题了吗? TypeScript or JavaScript type casting

N
Nitzan Tomer

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

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

我认为您不需要在 const toDo = req.body as IToDoDto; 中进行强制转换,因为 TS 编译器此时知道它是 IToDoDto
对于一般寻找类型断言的任何人,不要使用 <>。这已被弃用。使用as
javascript 中没有强制转换,所以如果“强制转换失败”,你不能抛出。” 我认为,更重要的是,TypeScript 中的接口是不可操作的;事实上,它们是 100% syntatic sugar。它们使概念上的结构更容易维护,但对转译的代码没有实际影响——正如 OP 的问题所证明的那样,imo 非常混乱/反模式.没有理由不匹配接口的东西不能在转译的 JavaScript 中抛出;这是 TypeScript 的一个有意识的(和糟糕的,imo)选择。
@ruffin 接口不是语法糖,但他们确实有意识地选择仅将其保留在运行时。我认为这是一个很好的选择,这样在运行时就没有性能损失。
Tomayto tomahto? TypeScript 中接口的类型安全不会扩展到您的转译代码,甚至在运行前,类型安全也受到严重 限制——正如我们在 OP 的问题中看到的那样,没有类型安全。 TS 可以说,“嘿,等等,你的 any 还不能保证是 IToDoDto!”,但 TS 选择不这样做。如果编译器只捕获 some 类型冲突,在转译的代码中没有(你是对的;我应该在原版中更清楚@那个),不幸的是,imo,[主要是?] 糖。
S
Sepehr

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


J
Jason

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

没有通过 linting

const x = new Obj(a as b);

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

通过 linting 和测试

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

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


我很高兴找到了这个答案,但请注意,如果您通过网络或其他应用程序发送“x”,您可能会泄露个人信息(例如,如果“a”是用户),因为“x”仍然具有“a”的所有属性,它们只是不能用于打字稿。
@ZoltánMatok 好点。此外,关于通过网络发送序列化对象,an argument 通过 JavaScript getset 方法用于 Java 样式的 getter 和 setter。