【问题标题】:Make sure object key belongs to a defined set确保对象键属于定义的集合
【发布时间】:2019-12-18 05:44:49
【问题描述】:

我正在尝试创建一个只能接受一组已定义键的对象类型。在下面的示例中,'1.1.1' | '1.1.2' | '1.1.3'

假设levelNum, subLevelNum and problemNum 是集合中的有效字符串。

type AllowedIndexes = '1.1.1' | '1.1.2' | '1.1.3';
type ProblemType = { [index in AllowedIndexes]?: Problem };

let problems: ProblemType = {};

// --> the following line gives the error <--
// `TS2322: Type 'string' is not assignable to type AllowedIndex.`
let ix:AllowedIndexes = `${levelNum}.${subLevelNum}.${problemNum}`;

problems[ix] = new Problem(....)

但是,如果我将错误的行写成如下,它可以工作:

let ix:AllowedIndexes = `${levelNum}.${subLevelNum}.${problemNum}` as AllowedIndexes;

我是在走正确的路,还是完全不去确保对象键属于定义的集合?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    你说得对。

    这一行

    let ix:AllowedIndexes = `${levelNum}.${subLevelNum}.${problemNum}`;
    

    Tell 的 TypeScript 您正在尝试将模板字符串(类型为 string)分配给预期类型为 AllowedIndexes 的值。然而,TypeScript 不能确定这将永远是正确的,并且随着您的修改:

    let ix:AllowedIndexes = `${levelNum}.${subLevelNum}.${problemNum}` as AllowedIndexes;
    

    您明确告诉它该值确实是AllowedIndexes。从类型的角度来看它是正确的,从逻辑/运行时的角度来看,当 levelNumsubLevelNumproblemNum 变量之一不正确时,它可能不正确,但在这种情况下 TypeScript 无法知道这一点。我能想到的对这段代码的唯一改进是对ProblemType 使用内置的Record 类型,如下所示:

    type ProblemType = Partial<Record<AllowedIndexes, Problem>>;
    

    请注意,我添加 Partial 只是因为您使用 ? 将对象的道具指定为可选

    【讨论】:

      【解决方案2】:

      除了与字符串文字类型的简单相等之外,没有其他方法可以限制 ts 中字符串的内容。

      也许改用元组类型,您可以将其限制为特定长度并使用文字类型来指定元组中每个项目的有效域。如果您的部分以表单字符串开头,您也可以使用自定义类型断言或类型保护来缩小类型:

      type AllowedIndexesItem = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0";
      type AllowedIndexes = [AllowedIndexesItem, AllowedIndexesItem, AllowedIndexesItem];
      
      declare let problemNum: string;
      declare let subLevelNum: string;
      declare let levelNum: string;
      
      function assertAllowedIndexesItem(o: string): asserts o is AllowedIndexesItem {
          if (!(o.length == 1 && o >= "0" && o < "9")) {
              throw new Error("Invlaid value")
          }
      }
      assertAllowedIndexesItem(levelNum);
      assertAllowedIndexesItem(subLevelNum);
      assertAllowedIndexesItem(problemNum);
      let ix:AllowedIndexes = [levelNum, subLevelNum, problemNum];
      
      

      Playground Link

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-30
        • 1970-01-01
        • 1970-01-01
        • 2011-06-24
        • 1970-01-01
        • 2012-05-19
        相关资源
        最近更新 更多