打字稿:“字符串”不能用于索引复杂对象上的类型

时间:2020-02-01 08:13:13

标签: typescript

我有这个复杂的物体

const classes = {
  Barbarian: {
    armorAndWeoponProficianies: [
      'lightAmour',
      'mediumArmour',
      'Sheilds',
      'simpleWeopons',
      'martialWeopons',
    ],
    class: 'Barbarian',
    description:
      'A fierce warrior of primitive background who can enter a battle rage',
    hitDie: '1d12',
    primaryAbility: 'STR',
    savingThrowProficianies: ['STR', 'CON'],
  },
  Bard: {
    armorAndWeoponProficianies: [
      'lightArmor',
      'simpleWeapons',
      'handCrossbows',
      'longswords',
      'rapiers',
      'shortswords',
    ],
    class: 'Bard',
    description:
      'An inspiring magician whose power echoes the music of creation',
    hitDie: '1d8',
    primaryAbility: 'CHA',
    savingThrowProficianies: ['DEX', 'CHA'],
  },
}

在这里,我想使用参数classType作为键,但是TypeScript不喜欢它

  const hitPointGenerator = (classType: string) => {
    const selectedClass = classes[classType].hitDie;
//                                  ^ Error
    console.log(selectedClass)
  };

我得到的错误是

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ Barbarian: { armorAndWeoponProficianies: string[]; class: string; description: string; hitDie: string; primaryAbility: string; savingThrowProficianies: string[]; }; Bard: { armorAndWeoponProficianies: string[]; ... 4 more ...; savingThrowProficianies: string[]; }; ... 9 more ...; Wizzard: { ...; }; }'.
  No index signature with a parameter of type 'string' was found on type '{ Barbarian: { armorAndWeoponProficianies: string[]; class: string; description: string; hitDie: string; primaryAbility: string; savingThrowProficianies: string[]; }; Bard: { armorAndWeoponProficianies: string[]; ... 4 more ...; savingThrowProficianies: string[]; }; ... 9 more ...; Wizzard: { ...; }; }'.ts(7053)

2 个答案:

答案 0 :(得分:3)

有多种解决方法:

使用正确的类型

classType参数更改为keyof typeof classes

const hitPointGenerator = (classType: keyof typeof classes) => {
    const selectedClass = classes[classType].hitDie;
    console.log(selectedClass)
};

这样的优点是您不会意外地用错误的键来调用它,例如

hitPointGenerator('Bard'); // OK
hitPointGenerator('Bart'); // compile error - notice the 't' at the end

TypeScript Playground Example

当您将鼠标悬停在typescript-playground的classType参数上时,您会看到类型为"Barbarian" | "Beard":这是Union Type,在这种情况下为{{1 }}(即更具体)

使用字符串索引签名

string

TypeScript Playground Example

使用此字符串索引签名,您可以将新项目动态添加到const classes: { [key: string]: any; } = { Barbarian: { ... 对象:

classes

有关index-signature的更多信息

具有接口的索引签名

要同时使用值的类型,可以定义一个接口,例如:

classes['new'] = {
  ...
}

TypeScript Playground Example

投射到任意

interface IMember {
  armorAndWeoponProficianies: string[];
  class: string;
  description: string;
  hitDie: string;
  primaryAbility: string;
  savingThrowProficianies: string[];
}

// we use an index signature to tell typescript that keys of type string are allowed
const classes: {
  [key: string]: IMember;
} = {
...
}

这仅仅是为了完成:我会避免这种情况。

TypeScript Playground Example

禁用`noImplicitAny`

const hitPointGenerator3 = (classType: string) => { const selectedClass = (classes as any)[classType].hitDie; // ^ cast console.log(selectedClass) }; -ref

中禁用noImplicitAny选项

当您将一些javascript代码迁移到打字稿时,这可能会很有用:我不会将其用于新项目,并尽可能尝试激活tsconfig.json

TypeScript Playground Example

答案 1 :(得分:2)

之所以发生这种情况,是因为classes只有两个有效键,但是字符串实际上可以是任何字符串。

也许尝试将函数签名更改为;

const hitPointGenerator = (classType: keyof typeof classes) => {
    const selectedClass = classes[classType].hitDie;
    console.log(selectedClass)
  };

这样只有"Barbarian" | "Bard"是classType的有效输入