【问题标题】:Template literal type inside object property falls back to primitive type in Typescript对象属性中的模板文字类型回退到 Typescript 中的原始类型
【发布时间】:2021-10-24 13:33:32
【问题描述】:

给定以下代码:

type Id = 1 | 2;

type Obj = {
    [key in `charge_${Id}_a` | `charge_${Id}_b`]: string
};
    
function func(id: Id) {
    const obj: Obj = {
        [`charge_${id}_a`]: "a",
        [`charge_${id}_b`]: "b",
    }

    return obj;
}

我希望 obj 符合 Obj,但我收到以下错误:

类型 '{ [x: string]: string; }' 缺少类型“Obj”的以下属性:charge_1_a、charge_2_a、charge_1_b、charge_2_b(2739)

意思是,Typescript 将obj 推断为{ [x: string]: string; } 而不是Obj

See playground

【问题讨论】:

  • 据我所知,它不应该遵守。 const obj: Obj = { charge_1_b: "foo" }; 这不会编译,因为它缺少 charge_1_acharge_2_acharge_2_b。自己试试。我明白了,TS 将charge_${id}_a 推断为string,而不是charge_1_a | charge_2_a
  • 不幸的是,对于具有计算属性的对象,我认为您无法推断出索引类型 {[x: string]: string} 以外的其他内容,但是您的 Obj 类型也存在问题。您将其定义为一个对象,其中包含所有 id 值的字段,但查看 func 似乎您希望每个 id 一个对象的联合:tsplay.dev/Wv8QRN

标签: typescript template-literals


【解决方案1】:

意思是,Typescript 将 obj 推断为 { [x: string]: string; } 并不是 作为对象。

不是因为这个。原因是因为有规则,其中一个说

您只能在索引时使用类型,这意味着您不能使用 const 来进行变量引用:

现在看你的例子,你有一些这样的

type Obj = {
    [key in `charge_${Id}_a` | `charge_${Id}_b`]: string
};

您违反了规则,因为 charge_${Id}_acharge_${Id}_b 是两个字符串文字,这意味着它们是常量,要做到这一点,您需要使它们倍增

type Obj = {
    [x: string]: string
};

但是这样做的全部意义是什么,人们会愿意插入他们想要阻止的 eva 只是遵守规则

const Options = `charge_${Id}_a` | `charge_${Id}_b`;

type Obj = {
    [key in Options]: string
};

等等,我不是说你需要索引类型,而不是常量,是的,这就是为什么我们需要不知名的keyof

function func(id: Id) {
    const obj: Obj = {
        [`charge_${id}_a` as keyof Options]: "a",
        [`charge_${id}_b` as keyof Options]: "b",
    }

    return obj;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2020-01-11
    • 1970-01-01
    • 2022-11-02
    • 2021-12-03
    • 1970-01-01
    相关资源
    最近更新 更多