类型防护将通用类型T缩小为Pick <T,U>

时间:2019-12-16 11:50:15

标签: typescript typescript-generics

我有一个类型保护,其唯一目的是检查对象中属性的存在并在其中具有一定的价值。

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

  

这是一个输入对象,如果类型保护成功,则输出是对象   具有 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
    )
}

但是我不断收到此错误消息,无法消除或理解

enter image description here

2 个答案:

答案 0 :(得分: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 & { [P in K]-?: Exclude<T[K], undefined> }可分配给T(这就是intersection T & ...所说的),并且对K键属性有额外的限制。请注意,{ [P in K]-?: Exclude<T[K], undefined> }也可以写成Required<Record<K, Exclude<T[K], undefined>>,这可能更容易理解。让我们确保它的行为符合预期:

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

答案 1 :(得分:0)

偶然地,我想到了这个解决方案,我认为这与显示错误的情况相同。

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

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")
}