【问题标题】:Type guard which narrows generic type T to Pick<T, U>将泛型类型 T 缩小为 Pick<T, U> 的类型保护
【发布时间】:2019-12-17 01:22:53
【问题描述】:

我有一个类型保护,其唯一目的是检查对象中属性的存在以及它是否具有某些价值。

如果类型保护检查成功,我想对编译器说这句话:

这是一个输入对象,如果类型保护成功则输出是一个对象 具有 lineHeight 属性

对于确切的对象,它看起来像这样:

type PickedLineHeight = Pick<TextStyle, "lineHeight">
type NonNullableLineHeight = Required<PickedLineHeight>

function hasLineHeight(style: object): style is NonNullableLineHeight {
    return (
        style.hasOwnProperty("lineHeight") &&
        (style as PickedLineHeight).lineHeight !== undefined
    )
}

如何开发更通用的函数版本,例如 hasProperty(style, prop)

我的尝试是:

function hasProperty<T extends { [key: string]: any}, U extends keyof T>(style: T, prop: U): style is Pick<T, U> {
    return (
        style.hasOwnProperty(prop) &&
        style[prop] !== undefined
    )
}

但我经常收到此错误消息,我无法消除或理解

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    我可能会这样输入hasProperty()

    function hasProperty<T extends object, K extends keyof T>(
        style: T,
        prop: K
    ): style is T & { [P in K]-?: Exclude<T[K], undefined> } {
        return style.hasOwnProperty(prop) && style[prop] !== undefined;
    }
    

    这应该反映出hasProperty() 将验证该属性是否存在而不是undefined。受保护的类型T &amp; { [P in K]-?: Exclude&lt;T[K], undefined&gt; } 可分配给T(这是intersection T &amp; ... 所说的)并且对K-keyed 属性有额外的限制。注意{ [P in K]-?: Exclude&lt;T[K], undefined&gt; }也可以写成Required&lt;Record&lt;K, Exclude&lt;T[K], undefined&gt;&gt;,这样可能更容易理解。让我们确保它的行为符合预期:

    interface Example {
        required: string;
        optional?: string;
        requiredButPossiblyUndefined: string | undefined;
        requiredButPossiblyNull: string | null;
    }
    
    function checkExample(ex: Example) {
        ex.required.toUpperCase(); // okay
    
        // hasProperty de-optionalizes optional properties
        ex.optional.toUpperCase(); // error, possibly undefined
        if (hasProperty(ex, "optional")) {
            ex.optional.toUpperCase(); // okay
        }
    
        // hasProperty removes undefined from list of possible values
        ex.requiredButPossiblyUndefined.toUpperCase(); // error, possibly undefined
        if (hasProperty(ex, "requiredButPossiblyUndefined")) {
            ex.requiredButPossiblyUndefined.toUpperCase(); // okay
        }
    
        // hasProperty doesn't do anything with null
        ex.requiredButPossiblyNull.toUpperCase(); // error, possibly null
        if (hasProperty(ex, "requiredButPossiblyNull")) {
            ex.requiredButPossiblyNull.toUpperCase(); // error, possibly null
        }
    }
    

    看起来不错。好的,希望有帮助。祝你好运!

    Link to code

    【讨论】:

    • 非常感谢!这正是我想要的。
    【解决方案2】:

    我偶然想到了这个解决方案,在我看来,这与显示错误的相同。

    但无论如何,这是毫无怨言的:

    function hasProperty<T extends object>(style: T, prop: keyof T): style is Pick<T, typeof prop> {
        return (
            style.hasOwnProperty(prop) &&
            style[prop] !== undefined
        )
    }
    
    function hasFontSize(style: TextStyle) {
        return hasProperty(style, "fontSize")
    }
    
    function hasLineHeight(style: TextStyle) {
        return hasProperty(style, "lineHeight")
    }
    

    【讨论】:

    • 这些类型表示对象的属性存在。但是 Typescript 仍然假定该属性下的值可以是 undefined
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    相关资源
    最近更新 更多