【问题标题】:Object with optional keys but with a mandatory value in TypeScript具有可选键但在 TypeScript 中具有强制值的对象
【发布时间】:2021-08-22 16:52:52
【问题描述】:

我想在 Typescript 中有一个带有 Record 的地图类型,其中键 in 是一个枚举。

我有这个枚举:

enum CatName {
  miffy = "miffy",
  boris = "boris",
  mordred = "mordred",
}

还有这个界面:

interface CatInfo {
  age: number;
  breed: string;
}

如果我使用这种类型:

type Cats = Record<CatName, CatInfo>

我必须使用枚举的所有键,这不是我想要的。

如果我使用这种类型:

type Cats = Partial<Record<CatName, CatInfo>>

我可以根据需要创建仅包含 Enum 的一些键的映射,但 CatInfo 现在可以未定义,我需要它是强制性的。

有没有办法实现带有一些键但具有强制值的映射?

如果有帮助的话,这里是 link 去游乐场。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    对于 4.3 及以下的 TypeScript 版本,没有直接的方法可以做到这一点。 Optional properties 允许缺失,但也允许存在-但-undefined。从某人只是读取此类属性的值的角度来看,没有区别;但从向此类属性写入值或通过inhasOwnProperty() 检查存在的角度来看,存在差异。问题microsoft/TypeScript#13195 要求 TypeScript 区分缺失和未定义。对于此类版本的 TypeScript,正确的做法可能是接受undefined。如果要检查属性是否存在并已定义,则不应使用inhasOwnProperty()

    if ("boris" in cats2) {
      cats2.boris.age.toFixed(2); // error in TS4.3-
    //~~~~~~~~~~~
    // Object is possibly 'undefined'.
    }
    
    if (cats2.boris !== undefined) {
      cats2.boris.age.toFixed(2); // okay in TS4.3-
    }
    

    相反,您应该只使用键索引对象并确保值不是undefined

    if (cats2.boris !== undefined) {
      cats2.boris.age.toFixed(2); // okay in TS4.3-
    }
    

    Playground link to code


    对于 TypeScript 4.4 及更高版本,如果您启用它,将会有一个新的编译器选项来修复 microsoft/TypeScript#13195。有关详细信息,请参阅microsoft/TypeScript#43947。 (更新 2021-06-10:此功能最初将通过新的 --strictOptionalProperties 编译器标志启用,该标志将包含在 --strict suite of compiler options 中。但是,根据 this comment,该标志将被重命名并从--strict 中删除,因此任何想在 TypeScript 4.4 及更高版本中看到此行为的人都需要通过一些名称尚未确定的编译器标志手动启用它。)

    如果您使用此功能,您将不再被允许将undefined 分配给可选属性(除非该属性的类型明确包含undefined),但您仍需要检查您为undefined 读取的属性:

    const cats2: Cats = {
      miffy: { age: 10, breed: "Persian" },
      boris: undefined, // error in TS4.4+!
      // Type 'undefined' is not assignable to type 'CatInfo'
    };
    

    您还可以使用inhasOwnProperty() 检查密钥是否存在,并在阅读时消除undefined 的可能性:

    if ("boris" in cats2) {
      cats2.boris.age.toFixed(2); // okay in TS4.4+
    }
    

    Playground link to code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-26
      • 2020-05-14
      相关资源
      最近更新 更多