【问题标题】:Omit never types in typescript省略从不输入打字稿
【发布时间】:2021-11-05 19:19:27
【问题描述】:

是否有可能以某种方式从 typescript 的类型中省略所有 never 类型?我有一个类型,它采用其他两种类型,并根据值生成第三种类型,并将所有不正确或不同值的元素设置为从不:

type MapForeignKeys<TExpandMap extends expandMap, TForeignKeys> = {
    [Prop in keyof TExpandMap]: 
        TExpandMap[Prop] extends { association: 'belongsTo', instance: BaseModel, foreignKey: any } 
        ? TExpandMap[Prop]['instance']['_creationAttributes'] | TExpandMap[Prop]['instance'] | TForeignKeys[TExpandMap[Prop]['foreignKey']] 
        : never 
                       
}

当我尝试使用此类型时,输出包含应设置为 never 的属性,而不是从类型定义中省略这些类型,因此这变得无法使用。

可以在this playground link中找到一个描述我的问题的简单示例

编辑:带有一些reproductible example of the problem的新链接

【问题讨论】:

    标签: typescript


    【解决方案1】:

    省略键的一种可能方法是使用as clause in mapped types

    您可以通过条件类型生成never 来过滤掉键

    type OmitNever<T> = { [K in keyof T as T[K] extends never ? never : K]: T[K] }
    

    所以这里我们将具有never 值的键替换为never 键,最终它们被省略了。

    Playground

    【讨论】:

    【解决方案2】:

    考虑这个例子:

    type WithNever = {
        a: string
        b: never
    }
    
    type Values<T> = T[keyof T]
    
    type OmitNever<T> = Pick<T, Values<{
        [Prop in keyof T]: [T[Prop]] extends [never] ? never : Prop
    }>>
    
    type Result = OmitNever<WithNever>
    
    const test: OmitNever<WithNever> = {
        a: 'test'
    }; // ok
    

    Playground

    OmitNever - 遍历每个键并检查它是否为never。如果是never,则保持原样,否则将值类型替换为键名。

    然后Values 获得所有生成值的联合。请记住,我们最终得到的对象是每个值都是条件类型的结果。

    如果我们有一个与never 的联合,比如"a" | never,TS 将删除never,只留下a。因此,Values 返回所有有效键的联合。

    最后一步,我们只需使用 Pick 与所有有效键的联合

    如果你想知道为什么我在这里使用方括号[T[Prop]] extends [never] - 请看这个answer

    更新

    // type Test = {
    //     [x: string]: never;
    //     foreignObject: string | number;
    //     manyObject: never;
    // }
    type Test = MapForeignKeys<expands, foreignKeys>
    

    您确定MapForeignKeys 按预期工作吗?因为它返回和索引对象,其中每个值都应为never

    【讨论】:

    • 好吧,这在操场上有效,但不幸的是在我的真实世界示例中无效。我有一个类型,即创建 never 类型(将其添加到我原来的问题中),当我在该类型上调用您的 OmitNever 类型时,所有非从不值都被忽略。我想这是因为我的原始类型是如何构造的,但我不确定:|
    • 我刚刚意识到,原始类型已经添加到问题中,所以基本上,提供的解决方案在更简单的示例中有效,但在该类型上使用时不起作用。我所做的是,我用问题中的类型调用了OmitNever&lt;&gt; 类型,因为它是通用参数。这确实从结果中删除了所有 never 值,但也删除了所有其他有类型的值。
    • @AdamBaranyai 请提供可重现的原始代码示例
    • 我用新的游乐场链接更新了问题
    • @AdamBaranyai 进行了更新
    猜你喜欢
    • 2022-11-22
    • 2019-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    相关资源
    最近更新 更多