【问题标题】:Required but possibly undefined type必需但可能未定义的类型
【发布时间】:2018-10-25 23:33:55
【问题描述】:

我想在 TypeScript 中创建一个类,它以一种要求具有该接口的所有属性(甚至是可选属性)的方式实现接口,但允许可选属性为undefined

这是Required_ish<T> 类型将比Required<T> 更宽,但比T 更严格,因为它需要我明确列出所有属性。然而,相同的值可以分配给Required_ish<T>T 的参数。

我试过这个,但它似乎和Required做同样的事情:

type Required_ish<T> = T & { [K in keyof T]-?: T[K] | undefined }

所需的属性:

interface Foo {
    a: string;
    b?: number;
}

class Bar1 implements Foo               { a = ''; } // allowed
class Bar2 implements Required_ish<Foo> { a = ''; } // error
class Bar3 implements Required<Foo>     { a = ''; } // error

class Bar4 implements Foo               { a = ''; b = undefined; } // allowed
class Bar5 implements Required_ish<Foo> { a = ''; b = undefined; } // allowed
class Bar6 implements Required<Foo>     { a = ''; b = undefined; } // error

class Bar7 implements Foo               { a = ''; b = 0; } // allowed
class Bar8 implements Required_ish<Foo> { a = ''; b = 0; } // allowed
class Bar9 implements Required<Foo>     { a = ''; b = 0; } // allowed

【问题讨论】:

    标签: typescript


    【解决方案1】:

    我终于找到了解决办法。而且它比我预期的更具可读性。

    type Required_ish<T> =
    {
        [K in keyof Required<T>]: T[K]
    };
    

    好的,但是为什么会这样呢?让我们分解一下。

    首先,我从同态mapped type开始:

    type Required_ish<T> = { [K in keyof T]: T[K] }
    

    映射类型是一种允许您修改类型但保持其内部结构(元组仍将是元组)和属性修饰符(只读,可选)的功能,除非您明确说明它。我刚刚写的这行或多或少是一种身份类型:对于T 的每个键,它返回的类型和修饰符与T 的类型和修饰符相同。

    现在有两个修饰符可以改变属性的必要性:

    { [K in keyof T]?:  T[K] } // add the optional modifier
    { [K in keyof T]-?: T[K] } // remove the optional modifier
    

    在这里使用-? 可能很诱人,但遗憾的是,这个修饰符做了两件事。它不仅从属性中删除了可选修饰符,还从结果类型中删除了 undefined。这意味着无论何时使用-?,都无法返回扩展未定义的类型。

    幸运的是,我们可以从T 而不是从Required&lt;T&gt; 获取密钥。由于编译器从左侧(: 之前的部分)获取所有修饰符,因此该属性将具有与 Required&lt;T&gt;[K] 相同的修饰符。这意味着它永远不会是可选的,readonly 修饰符将保持不变。由于我们没有使用 -? 修饰符,T[K] 将保持不变并且可能未定义。

    通过这种方式,我们有效地绕过了 -? 的副作用,并且生成的类型完全符合我的要求。

    【讨论】:

    • 请描述为什么这个代码是一个可能的解决方案。
    • 我重新审视了代码,思考了一下,发现有一个更简单的解决方案。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-11-18
    • 2018-06-30
    • 2017-09-21
    • 2018-12-18
    • 2020-05-31
    • 2016-06-29
    • 2017-12-12
    • 1970-01-01
    相关资源
    最近更新 更多