Typescript 通用消息工厂
Posted
技术标签:
【中文标题】Typescript 通用消息工厂【英文标题】:Typescript Generic message factory 【发布时间】:2021-09-30 20:38:54 【问题描述】:我的应用程序中有一个用例,我希望能够使用简单的 TypeScript 泛型指定消息结构,并附带一个简单的消息工厂。我想出了以下几点:
export type Message<
T extends string,
P extends Record<string, any> = Record<string, never>
> =
type: T;
payload: P;
;
export const msg = <M extends Message<string, Record<string, any>>>(
type: M['type'],
payload: M['payload']
): M => ( type, payload );
type UserRegistered = Message<'UserRegistered', name: string >;
const message = <UserRegistered>msg('UserRegistered', name: 'Test' );
但我在 ): M => ( type, payload );
行上遇到 TS2322 错误:
错误 TS2322: 类型 ' type: M["type"];有效载荷:M[“有效载荷”]; ' 不可分配给类型 'M'。 ' 类型:M[“类型”];有效载荷:M[“有效载荷”]; ' 可分配给“M”类型的约束,但“M”可以用约束“Message
>”的不同子类型来实例化。
我正在努力弄清楚这可能是一种类型安全风险,以及为什么它不能转换,因为我本质上是在解构和重构相同的类型。
(如果您质疑这个瘦工厂层的实用性,我指望它通过大量预构建的命名工厂函数帮助可维护性)
【问题讨论】:
【参考方案1】:根据经验,请尝试从下到上推断函数参数。
我的意思是,不要试图推断 <M extends Message<string, Record<string, any>>
整个 M
泛型类型。首先推断出这个类型的每个嵌套属性,然后就可以全部放在一起了。
至少在您的情况下,没有必要使用显式返回类型。请记住,TS 具有结构类型系统,而不是名义上的。
在调用函数时避免使用显式泛型。 99% 是没有必要的。 TS 应该为你推断所有类型
export type Message<
T extends string,
P extends Record<string, any> = Record<string, never>
> =
type: T;
payload: P;
;
export const msg = <
Type extends string,
Payload extends Record<string, any> = Record<string, never>
>(
type: Type,
payload: Payload
): Message<Type, Payload> => ( type, payload )
type UserRegistered = Message<'UserRegistered', name: string >;
const message = msg('UserRegistered', name: 'Test' )
/**
* UserRegistered is redundant here
*/
const message_: UserRegistered = msg('UserRegistered', name: 'Test' )
Playground
Here,在我的文章中你可以找到更多关于推断函数参数的信息
【讨论】:
感谢您的广泛而彻底的回复!这个周末我需要再读几遍(已经很晚了),但这似乎确实起到了作用。我使用显式泛型来要求传递预期的有效负载形状,所以我不能调用msg('UserRegistered', wrong: 'payload' )
。以上是关于Typescript 通用消息工厂的主要内容,如果未能解决你的问题,请参考以下文章