TS2339:联合类型 - 属性字符串|上不存在属性未定义

时间:2018-06-13 15:12:52

标签: typescript types typescript2.0 union-types

我的联合类型有问题,如下所示:

type RepeatForm = {
    step:
        | {
              repeat: false;
          }
        | {
              repeat: true;
              from: undefined;
          }
        | {
              repeat: true;
              from: string;
              by?: string;
          };
};

我有以下功能,如果它在那里我想获得by的值:

export const getByField = (form: RepeatForm) => {
    if (form.step.repeat === false || form.step.from === undefined) {
        return null;
    }
    const x = form.step.from;
    return form.step.by;
};

我收到此错误:Property 'by' does not exist on type '{ repeat: true; from: undefined; } | { repeat: true; from: string; by?: string | undefined; }'. Property 'by' does not exist on type '{ repeat: true; from: undefined; }'.

这对我来说非常混乱,因为TypeScript知道form.step.fromundefined不同,他甚至会将变量类型x插入到string

这个问题的原因是什么?我怎样才能访问by属性?

1 个答案:

答案 0 :(得分:1)

受歧视联盟的原始PR非常具体,因为歧视字段必须是string字面类型(可选择添加对boolean和{{1}的支持似乎已经发生的文字类型)。因此,您根据字段类型(number vs string)进行区分的用例似乎不受支持。例如,这不起作用:

undefined

我们可以使用条件类型和自定义类型保护来使事情有效:

let u!: { v: number, n: number } | { v: string, s: string}
if(typeof u.v === 'number') {
    u.n // not accesible, type not narrowed 
}

我们还可以创建此函数的通用版本,允许以任何类型缩小:

function isUndefined<T, K extends keyof T>(value : T, field: K) : value is Extract<T, { [P in K] : undefined }> {
    return !!value[field]
}

export const getByField = (form: RepeatForm) => {
    if (form.step.repeat === false || isUndefined(form.step, 'from')) {
        return null;
    }
    const x = form.step.from;
    return form.step.by;
};