【问题标题】:Typescript Generic message factoryTypescript 通用消息工厂
【发布时间】: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 =&gt; ({ type, payload }); 行上遇到 TS2322 错误:

错误 TS2322: 类型 '{ type: M["type"];有效载荷:M[“有效载荷”]; }' 不可分配给类型 'M'。 '{ 类型:M[“类型”];有效载荷:M[“有效载荷”]; }' 可分配给“M”类型的约束,但“M”可以用约束“Message>”的不同子类型来实例化。

我正在努力弄清楚这可能是一种类型安全风险,以及为什么它不能转换,因为我本质上是在解构和重构相同的类型。

(如果您质疑这个瘦工厂层的实用性,我指望它通过大量预构建的命名工厂函数帮助可维护性)

【问题讨论】:

    标签: typescript generics type-inference typescript-generics


    【解决方案1】:

    根据经验,请尝试从下到上推断函数参数。 我的意思是,不要试图推断 &lt;M extends Message&lt;string, Record&lt;string, any&gt;&gt; 整个 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' })
    猜你喜欢
    • 2017-08-05
    • 1970-01-01
    • 2014-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    相关资源
    最近更新 更多