在 TypeScript 中声明对象类型

4
需要声明一个对象类型。出现以下错误:
 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抛出以下错误:

类型'{[x: string]: { color: string }}'缺少类型'Record'的以下属性:mercedes,mercedes-sedan,mercedes-hatch


注:该错误是TypeScript编译器对代码进行类型检查时发现的。
3个回答

5

有两个问题,首先你写了type CarKeys = "mercedes" | "mercedes_sedan" | "mercedes_hatch",都是下划线,但是KEY_MAP中的值却是连字符,这是不匹配的,你可能需要修复它。

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

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

为了解决这个问题,你可以在KEY_MAP的末尾添加as const

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

或者,你可以将其转换为枚举

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

3
你的代码中存在错误,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:没错,分号需要替换成逗号。我忘记在我的代码中注明这一点了,我已经修复了。 - H.B.

3

首先,在使用TypeScript时,您不需要使用键值映射+字符串字面类型。您可以选择其中之一,因为它将确保类型安全性。同时,使用枚举而不是标准JS对象的方法将更加合适,因为它将解决值和类型在一个语言结构中的问题。只考虑使用枚举的解决方案:

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 你能看一下这个回答吗?我认为它在多个层面上回答了你的问题。谢谢。 - Maciej Sikora

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接