【问题标题】:How to use ternary operator on nested object field to validate my typescript type如何在嵌套对象字段上使用三元运算符来验证我的打字稿类型
【发布时间】:2021-09-09 00:59:30
【问题描述】:

我在这里做错了什么还是设计使然?

我希望能够写出这样的东西。

type MyType = {
    greeting: string;
    value?: { valueType: string; value?: string };
};

function generate(name: string, input?: Partial<MyType['value']>): MyType {
    return {
        greeting: `Hello, ${name}`,
        value: input?.valueType ? input : undefined,
    };
}

如您所见,我使用三元运算符来验证我的 input 对象是否有效,但 TypeScript 抱怨并给出错误:

类型“未定义”不可分配给类型“字符串”。(2322)


TypeScript Playground Example

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    如果您重新定义对象属性,Typescript 缩小功能会按预期工作。工作示例:

    代码:

    type MyType = {
        greeting: string;
        value?: { valueType: string; value?: string };
    };
    
    function generate(name: string, input?: MyType['value']): MyType {
        return {
           greeting: `Hello, ${name}`,
           value: input?.valueType ?  {
                valueType: input.valueType,
                value: input.value
            } : undefined,
        };
    }
    

    @见https://github.com/microsoft/TypeScript/issues/29827

    【讨论】:

    • 这会改变语义并且不允许传递缺少valueType 属性的input,而OP 的代码允许这样做。我只是在评论中提到它 - 目前还不清楚 OP 是否真的需要将没有valueType 的对象传递给函数。
    • 我也希望能够像这样调用函数:generate('Jógvan', { value: 'without a type' });
    • 我现在更了解您的意图。我编辑了我的帖子,保留了使用这样的对象的可能性:{ value: 'obj with no valueType' }
    • 您提供的正是我想要避免的,但我明白这正是我们所需要的。但是这里有人用 3 行显示为什么不支持我想要的:github.com/microsoft/TypeScript/issues/…
    【解决方案2】:

    要了解出了什么问题,首先,让我们检查返回位置的类型。它的value 属性具有以下类型(如预期的那样):

    { valueType: string; value?: string | undefined; } | undefined;
    

    让我们也看看input?.valueType ? input : undefined 给我们带来了什么:

    Partial<{
        valueType: string;
        value?: string | undefined;
    }> | undefined
    

    这就是问题所在:您告诉编译器您希望 valueTypestring 类型,但您实际尝试分配给它的是 string | undefined(显然是因为 Partial 助手使 @987654331 @属性可选)。

    Partial&lt;T&gt; | undefined 是推断出来的,因为您还告诉编译器 generate 函数接受 Partial&lt;MyType['value']&gt; 作为第二个参数。现在,你能做些什么呢?在不改变语义的情况下,唯一合理的选择是将valueType 也设为可选:

    type MyType = {
        greeting: string;
        value?: {
            valueType?: string;
            value?: string;
        };
    };
    
    function generate(name: string, input?: Partial<MyType['value']>): MyType {
        const value = input?.valueType ? input : undefined;
        return { greeting: `Hello, ${name}`, value }; //OK
    }
    

    这可能不是您想要的。但是,为了实现您的目标,您需要可选链接来充当类型保护并“映射”您告诉编译器的类型为 Partial 以删除修饰符。这可以通过用户定义的type guard 实现,如下所示:

    const withType = (val: Partial<MyType["value"]>) : val is Exclude<MyType["value"], undefined> => !!val?.valueType;
    
    function generate(name: string, input?: Partial<MyType['value']>): MyType {
      const value = withType(input) ? input : undefined;
      return { greeting: `Hello, ${name}`, value }; //OK
    }
    

    Playground

    【讨论】:

      猜你喜欢
      • 2022-07-21
      • 2020-03-07
      • 2020-11-30
      • 2022-10-14
      • 1970-01-01
      • 2019-04-30
      • 2021-12-06
      • 1970-01-01
      • 2022-06-28
      相关资源
      最近更新 更多