非常类似于Using partial shape for unit testing with typescript,但我不明白为什么Partial类型被视为与完整版本不兼容。
我有一个单元测试,如果AWS lambda事件中的body
无效,则检查lambda是否返回400。为了避免给我的同事制造噪音,我不想创建具有完整APIGatewayProxyEvent
的所有属性的invalidEvent
。因此使用Partial<APIGatewayProxyEvent>
。
it("should return 400 when request event is invalid", async () => {
const invalidEvent: Partial<APIGatewayProxyEvent> = {
body: JSON.stringify({ foo: "bar" }),
};
const { statusCode } = await handler(invalidEvent);
expect(statusCode).toBe(400);
});
字符串const { statusCode } = await handler(invalidEvent);
行编译失败:
Argument of type 'Partial<APIGatewayProxyEvent>' is not assignable to parameter of type 'APIGatewayProxyEvent'.
Types of property 'body' are incompatible.
Type 'string | null | undefined' is not assignable to type 'string | null'.
Type 'undefined' is not assignable to type 'string | null'.ts(2345)
型
我知道APIGatewayProxyEvent
的body可以是string | null
(从类型上看),但是string | null | undefined
是从哪里来的?为什么我的body
-这是一个字符串-不是APIGatewayProxyEvent
的有效body
如何使用TypeScript Partials测试AWS Lambda?
我可以使用as
to do type assertions,但我发现Partials更显式。下面的代码可以工作:
const invalidEvent = { body: JSON.stringify({ foo: "bar" }) } as APIGatewayProxyEvent;
型
更新:使用Omit和Pick创建新类型
type TestingEventWithBody = Omit<Partial<APIGatewayProxyEvent>, "body"> & Pick<APIGatewayProxyEvent, "body">;
it("should return 400 when request event is invalid", async () => {
const invalidEvent: TestingEventWithBody = { body: JSON.stringify({ foo: "bar" }) };
const { statusCode } = await handler(invalidEvent);
expect(statusCode).toBe(400);
});
型
失败:
Argument of type 'TestingEventWithBody' is not assignable to parameter of type 'APIGatewayProxyEvent'.
Types of property 'headers' are incompatible.
Type 'APIGatewayProxyEventHeaders | undefined' is not assignable to type 'APIGatewayProxyEventHeaders'.
Type 'undefined' is not assignable to type 'APIGatewayProxyEventHeaders'.ts(2345)
型
2条答案
按热度按时间eqqqjvef1#
我不明白为什么Partial类型被认为与完整版本不兼容
从根本上说,这是不可避免的-您从要求
body
属性为string | null
的东西开始,并创建了具有较弱要求string | null | undefined
的东西。在这种情况下,您确实提供了body
,但这并不重要,因为handler
只通过Partial<APIGatewayProxyEvent>
接口看到invalidEvent
,编译器知道属性 could 正如您所看到的,如果您修补了一个属性,使其再次被要求,它只会抱怨下一个属性。如果您不拥有
handler
API,您实际上只有三种选择,其中没有一种是理想的:1.实际上提供了一个完整的
APIGatewayProxyEvent
(见结尾的快捷方式);1.向编译器声明您的测试对象 * 是 * 一个带有类型Assert的完整
APIGatewayProxyEvent
;或者1.告诉编译器不要用
// @ts-ignore
注解来检查它。使用
Partial
通常只是选项2中的一个步骤,使用:字符串
而不是:
型
如果您拥有 *
handler
的API,最好的方法是应用interface segregation principle,并具体说明它实际需要做什么来完成其工作。如果只是body
,例如:型
一个完整的
APIGatewayProxyEvent
仍然是handler
的有效参数,因为它确实有一个body
(而且它还有其他属性是无关紧要的,它们是通过HandlerEvent
不可访问的)。这也是关于你实际从完整对象中消费的内容的内置文档。在你的测试中,你现在可以创建一个更小的对象:
型
作为奖励,如果后来发现你需要访问
handler
中更多的事件属性,你可以更新类型:型
如果你需要更新测试数据来考虑这个问题,你会在任何地方得到错误。这在
const invalidEvent = { ... } as APIGatewayProxyEvent;
中不会发生,你必须通过查看哪些测试在运行时失败来跟踪更改。我见过的选项1的另一个快捷方式是在partial周围 Package 一个函数,提供合理的默认值:
型
在这种情况下,你应该尽可能地减少默认值(
null
,0
,""
,空对象和数组,...),以避免依赖于它们的任何特定行为。xoefb8l82#
这里的问题是partial类型将所有对象属性转换为optional:
字符串
在
MyObj
类型中,myKey
类型是string | null
。当我们将其转换为MyPartialObj
时,myKey
类型变为可选,因此可能是undefined
。因此现在其类型是string | null | undefined
你的
APIGatewayProxyEvent
类型期望body
是string | null
,然而,因为你已经使它成为partial,你说body
* 可能 * 也是undefined
。是的,你已经定义了它,但你从来没有做过type narrowing来验证它确实是一个字符串。所以所有的TypeScript必须离开的是你分配的类型,这也是Partial。**更新:**扩展@jonrsharpe在评论中所说的内容。我以前的解决方案似乎不起作用,它只是将错误推到
APIGatewayProxyEvent
中的下一个属性上。请参阅他们的答案。问题是你试图模拟一部分数据,而类型期望所有数据都存在。可能最简单的方法是为每个属性创建一个具有最小值的对象,而不是试图伪造它。你可以 * 使用as
,但这首先违背了使用类型系统的全部意义。**上一个答案:**一个解决方案可能是让所有值都是可选的,除了
body
:型
另外,避免像瘟疫一样使用
as x
,或者除非你完全确定你在做什么。