缩小TypeScript索引类型

时间:2018-06-08 13:34:05

标签: typescript

我有以下应该编译的代码,但它不是:

interface A {
    field: string;
    fieldB: { fieldC: string;}
}

function mixPropValue<P extends keyof A>(propName: P, value: A[P]) {
    if (propName === 'fieldB') {
        // value is always in type of { fieldC:string }
        value.fieldC; // Error: Property 'fieldC' does not exist on type 'A[P]'.
    }
}

Playground

是否可以让TypeScript知道第一个if分支下的缩小类型?当然我可以使用类型转换来编译代码,但我想避免它。

2 个答案:

答案 0 :(得分:1)

您可以缩小与检查属性名称相同匹配的类型,以便将类型解析为更窄的选项:

interface A {
    field: string;
    fieldB: { fieldC: string;}
}

function isFieldB<P extends keyof A>(propName: P, prop: { fieldC: string } | any): prop is { fieldC: string } {
    return propName === 'fieldB';
}

function mixPropValue<P extends keyof A>(propName: P, value: A[P]) {
    if (isFieldB(propName, value)) {
        value.fieldC;
    }
}

编译器的未来版本可能会使这种情况变得多余,但如果他们这样做会有一个令人印象深刻的飞跃,因为有合理数量的&#34;连接点&#34;这里。 TypeScript团队经常管理它。

答案 1 :(得分:0)

编译器不会根据suck测试缩小类型,最好的选择是自定义类型保护:

function isProp<P extends keyof A>(value: A[keyof A], targetProp: P, testProp : keyof A) : value is A[P] {
    return targetProp === testProp;
}
function mixPropValue<P extends keyof A>(propName: P, oldValue: A[P], newValue: A[P]) {
    if (isProp(oldValue, 'fieldB', propName) && isProp(newValue, 'fieldB', propName)) {
        // oldValue, newValue here are always in type of { fieldC:string }
        return { ...oldValue, ...newValue }; // Error: Spread types may only be created from object types.
    }
    return newValue;
}