【问题标题】:Declaring object type in typescript在打字稿中声明对象类型
【发布时间】:2019-11-27 21:25:49
【问题描述】:

需要声明一个对象类型。得到下面提到的错误:

 type CarKeys = "mercedes" | "mercedes-sedan" | "mercedes-hatch";

    interface Car { color: string; } 

    const KEY_MAP = { mercedes: 'mercedes', mercedes_sedan: 'mercedes-sedan', mercedes_hatch: 'mercedes-hatch'};

        const carType:Record<CarKeys, Car> = {
         [KEY_MAP.mercedes]:{ color: 'red'},
         [KEY_MAP.mercedes_sedan]: {color: 'yellow'},
         [KEY_MAP.mercedes_hatch]: {color: 'black'}
        };

TypeScript 抛出以下错误:

Type'{[x: string]: { color: string }}' 缺少“记录”类型的以下属性:mercedes、mercedes-sedan、mercedes-hatch`

【问题讨论】:

    标签: typescript


    【解决方案1】:

    两件事,首先你写了type CarKeys = "mercedes" | "mercedes_sedan" | "mercedes_hatch",都带有下划线,但KEY_MAP 中的值有连字符,这是你可能想要修复的不匹配。 p>

    其次,默认情况下,TS 会推断typeof KEY_MAP{ mercedes: string; ... } 而不是{ mercedes: "mercedes", ... }

    这意味着 typeof [KEY_MAP.mercedes] 实际上是 string,而不是 "mercedes" 字符串文字,因此 typeof carType 实际上是 { [key: string]: Car },这就是错误的原因。

    要修复它,您可以在KEY_MAP 的末尾添加as const

    const KEY_MAP = {
      mercedes: 'mercedes',
      mercedes_sedan: 'mercedes-sedan',
      mercedes_hatch: 'mercedes-hatch'
    } as const;
    

    或者,您可以将其转为enum

    enum KEY_MAP {
      mercedes = 'mercedes',
      mercedes_sedan = 'mercedes-sedan',
      mercedes_hatch ='mercedes-hatch'
    }
    

    【讨论】:

      【解决方案2】:

      您的代码中有错误,KEY_MAP 中的值实际上与CarKeys 中指定的值不匹配。另外,carType 中的分号必须是逗号。

      要解决手头的问题,您可以使用as const。在您的代码中,KEY_MAP 的解析类型为:

      const KEY_MAP: {
          mercedes: string;
          mercedes_sedan: string;
          mercedes_hatch: string;
      }
      

      这样指定:

      const KEY_MAP = {
          mercedes: 'mercedes',
          mercedes_sedan: 'mercedes_sedan',
          mercedes_hatch: 'mercedes_hatch'
      } as const;
      

      那么解析的类型将是:

      const KEY_MAP: {
          readonly mercedes: "mercedes";
          readonly mercedes_sedan: "mercedes_sedan";
          readonly mercedes_hatch: "mercedes_hatch";
      }
      

      应该编译。

      【讨论】:

      • @Andreas:对,分号需要换成逗号。忘了注意我在我的代码中也修复了这个问题......
      【解决方案3】:

      首先,在使用 TypeScript 时,您不需要使用 Key -> Value map + String 文字类型。您可以选择两者之一,因为它将确保类型安全。使用 Enum 代替标准 JS 对象的方法也更合适,因为它可以解决一种语言结构中的值和类型。考虑仅使用 Enum 的解决方案:

      interface Car { color: string; } 
      
      enum KEY_MAP {
          mercedes = 'mercedes',
          mercedes_sedan = 'mercedes_sedan',
          mercedes_hatch = 'mercedes_hatch'
      }
      
      const carType: Record<KEY_MAP, Car> = {
          [KEY_MAP.mercedes]:{ color: 'red'},
          [KEY_MAP.mercedes_sedan]: {color: 'yellow'},
          [KEY_MAP.mercedes_hatch]: {color: 'black'}
      }
      

      仅使用字符串文字的解决方案也是完全有效且类型安全的。考虑:

      type CarKeys = "mercedes" | "mercedes_sedan" | "mercedes_hatch";
      
      interface Car { color: string; } 
      
      const carType: Record<CarKeys, Car> = {
          mercedes:{ color: 'red'},
          mercedes_sedan: {color: 'yellow'},
          mercedes_hatch: {color: 'black'}
      } // carType cannot be created with wrong key or value type
      

      字符串文字类型不应被视为“魔术字符串”,因为它被编译器监视并且类型安全。我们不需要创建一些中间结构来直接使用它。

      最后一点也很重要。您可以通过为 KEY_MAP 指定正确的类型来直接修复您的实现。

      type CarKeys = "mercedes" | "mercedes_sedan" | "mercedes_hatch";
      
      interface Car { color: string; } 
      
      const KEY_MAP: { [P in CarKeys]: P } = { mercedes: 'mercedes', mercedes_sedan: 'mercedes_sedan', mercedes_hatch: 'mercedes_hatch'};
      
      const carType:Record<CarKeys, Car> = {
          [KEY_MAP.mercedes]:{ color: 'red'},
          [KEY_MAP.mercedes_sedan]: {color: 'yellow'},
          [KEY_MAP.mercedes_hatch]: {color: 'black'}
      }; // no issues
      

      核心是{ [P in CarKeys]: P }。我们是说我们的对象具有来自CarKeys 的确切单个项目作为键和值。

      【讨论】:

      • @gaurav-soni 你能看看这个答案吗?我认为它在多个层面上回答了你的问题。谢谢。
      猜你喜欢
      • 2021-01-20
      • 2018-11-06
      • 2020-01-08
      • 2019-02-16
      • 2022-01-26
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 2017-08-12
      相关资源
      最近更新 更多