【问题标题】:How to type a standalone object in TypeScript?如何在 TypeScript 中键入独立对象?
【发布时间】:2021-08-27 09:41:05
【问题描述】:
AWSMock.mock("SQS", "receiveMessage", {
    Messages: [
        {
            MessageId: "abcd",
            Body: "sample body",
        },
    ],
});

在上面的示例中,如何将对象键入为ReceiveMessageResult 实例?

我无法键入 AWSMock.mock() 方法,因为这是第 3 方模拟库中的通用方法。

????️ 这不起作用,因为它不会捕获任何类型错误(例如,任何缺少的字段都不会触发错误):

AWSMock.mock("SQS", "receiveMessage", {
    Messages: [
        {
            MessageId: "abcd",
            Body: "sample body",
        },
    ],
} as ReceiveMessageResult);

????️这可以工作,但我不想通过额外的变量:

const response: ReceiveMessageResult = {
    Messages: [
        {
            MessageId: "abcd",
            Body: "sample body",
        },
    ],
};
AWSMock.mock("SQS", "receiveMessage", response);

有什么方法可以即时键入对象吗?

【问题讨论】:

  • 我很遗憾地认为您的第三种解决方案是做到这一点的唯一方法。
  • 你用的是哪个ts版本?我尝试了一个与对您不起作用的代码类似的代码,并且它具有自动完成功能。您也可以尝试旧断言:..."receiveMessage", <ReceiveMessageResult>{ Messages: [...
  • @EcksDy 是的,确实我确实得到了自动补全,但类型没有经过验证。我的意思是,如果我不尊重接口,那么 TypeScript 就不会显示任何错误。
  • @MatthieuNapoli 那么断言不是这项工作的工具。断言是告诉 TS 忽略它所知道的关于目标的任何事情,并接受你的断言作为事实。根据该定义,它不能向您显示任何错误,因为您使用断言语句覆盖了任何可能的错误。它甚至不会寻找类型和实际对象之间的差异。您的最后一个示例有效,因为它不是断言。您正在创建一个变量response,它只能接收适合ReceiveMessageResult 的对象。如果你这样做 const response: ReceiveMessageResult = 3; 那将是一个错误。
  • @MatthieuNapoli 执行const response: ReceiveMessageResult = 3 as ReceiveMessageResult; 不会引发编译错误,因为您将覆盖 ts 对 3(数字)的了解并将其标记为 as ReceiveMessageResult。您会收到“ts(2352)”错误,告诉您先转换为未知数,然后再转换为 ReceiveMessageResult,但它仍会编译。

标签: typescript


【解决方案1】:

我能想到几个选项:

  1. 在目标项目中创建一个具有更好类型的 PR。但是我看到已经有a PR from 2019 并且没有合并。
  2. 不要使用维护不善的第 3 方库。
  3. 覆盖类型。见this answer。但是你必须自己维护它。
  4. 按照您的建议使用变量(恕我直言,这可能是最直接的选项)
  5. 创建包装函数:
function t<T>(input: T): T {
  return input;
}

interface Book {
  id: number;
  title: string;
}

function log(input: any): any {
  console.log(input);
}

log({title: 'Galaxy Guide'} as Book); // Does not complain
log(t<Book>({title: 'Galaxy Guide'})); // Complains that id is missing
  1. 创建一个重载函数并在任何地方使用它:
function myAwsMock<T>(service: string, method: string, replace: T): void {
  AWSMock.mock(service, method, replace);
}

【讨论】:

  • 1 和 2 无关,我对 sinon 也有同样的问题。你说的3是什么意思?和5有区别吗?我认为我们正朝着“不可能”的答案前进。
  • 我已经编辑了我的答案。如果您想使用 3,则 1 是相关的。您基本上可以从那里复制类型。我从来没有使用过 Sinon,但他们的类型看起来肯定比这个库好得多。
【解决方案2】:

首先,我认为mock 函数的重载应该重新排序,但这与我们的问题没有直接关系。 我发了PR

为了使其工作,您应该编写自己的aws-sdk-mock 模块的自定义声明。

  1. 在您的根文件夹中创建typings.d.ts 文件。
  2. 将此代码粘贴到typings.d.ts
declare module 'aws-sdk-mock' {
    function mock<T>(service: "SQS", method: "receiveMessage", replace: T): void;
}

添加通用T 很重要,因为它比内置声明中的any 更具体。

  1. 那么你应该明确地使用泛型参数:

import AWSMock from 'aws-sdk-mock';

type Message = {
    MessageId: string;
    Body: string;
}

type ReceiveMessageResult = {
    Messages: Message[],
}

AWSMock.mock<ReceiveMessageResult>("SQS", "receiveMessage", {
    Messages: [
        {
            MessageId: "abcd",
            Body: "sample body",
            x: 1 // expected error
        },
    ],
});

瞧,它有效。

我试图让它在没有显式泛型参数的情况下工作,但是因为内置类型中的第三个参数有any类型,所以不可能在any之后使用更具体的类型。

【讨论】:

  • 感谢您的回答,但我的问题很笼统。它与 aws-mock 无关,它实际上发生在不同的地方,在这些地方引入自定义类型不是一种选择,或者不是我每次都想做的事情。
  • @MatthieuNapoli 但您可以以相同的方式为任何第三方库编写自己的自定义重载
  • 是的,但是如果我遇到了所有这些麻烦,那么我还不如创建一个无用的变量。我的目标是避免不得不采取变通办法。
  • 我不会说这是一种变通方法,这正是 TS 的工作原理,但肯定没问题。
【解决方案3】:

这是不可能的。

我的问题是关于在没有解决方法的情况下在 TypeScript 中执行此操作(我已经有了)。所有其他问题都提供了新的和不同的解决方法。

我相信这些其他答案仍然有用(请随意阅读它们),但我想为那些面临与我相同问题的人标记一个明确的答案:没有原生解决方案。没有变通办法就无法完成。

【讨论】:

    猜你喜欢
    • 2021-11-09
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-16
    • 2019-02-04
    • 1970-01-01
    相关资源
    最近更新 更多