无法访问对象的深层 properties/values

Can't access deep properties/values of object

所以下面是我的示例测试代码,用于实施更广泛的解决方案。我创建了一个“服务”对象,每个 属性 是服务名称,值为服务对象。每个服务对象都包含一个 属性 个“命令”,其值是一个命令对象(类)。

这些命令是通过 CLI 执行的,它总是 returns 一个字符串,然后将其拆分。数组的索引 0 将是服务名称,而索引 1 将是命令的名称。

// Example Classes

class A {

    init() {

        console.log('I Am A');
    }
}

class B {

    init() {

        console.log('I Am B')
    }
}

// Example Services Structure

export const services = {
    service1: {
        commands: {
            a: A
        }
    },
    service2: {
        commands: {
            b: B
        }
    }
}

// Type Declarations

export type Services = typeof services;
export type ServicesKeys = keyof Services;

// Testing

const input = (prompt('Choose a Service') || '').split(' ');

if (input.length !== 2) Deno.exit();

if (input[0] in services) {

    const sKey = input[0] as ServicesKeys;
    const service = services[sKey];

    const commands = service.commands;

    if (input[1] in commands) {

        // Run into issues here as `keyof typeof commands` is `never`
        new commands[input[1] as keyof typeof commands]();
    }
}

new commands[input[1] as keyof typeof commands](); 之前一切正常,因为 keyof typeof commands 的类型设置为从不。我理解为 commands 不能有 ab 所以 keyof 必须是 never 但我该如何处理这个?

您只需定义 services 对象的类型,就像下面的重构一样。如果你想限制结构的任何部分的键,你可以简单地用你的 union/enum/etc.

替换 string

注意:我提供了代码中使用的 Deno 命名空间 API 的替代品,以便您可以直接在浏览器中 运行 游乐场示例。

TS Playground link

const Deno = {
  exit (code: number = 0): never {
    throw new Error(`Exited with code ${code}`);
  }
};

// Example Classes

type Command = {
  init (): void;
};

class A implements Command {
  init () {
    console.log('I Am A');
  }
}

class B implements Command {
  init () {
    console.log('I Am B')
  }
}

// Type Declarations

type Service = {
  commands: {
    [commandName: string]: new () => Command;
  };
};

type Services = { [serviceName: string]: Service };

// Example Services Structure

const services: Services = {
  service1: {
    commands: {
      a: A
    }
  },
  service2: {
    commands: {
      b: B
    }
  }
}

// Testing

const input = (prompt('Choose a Service') || '').split(' ');

if (input.length !== 2) Deno.exit();

const [serviceName, commandName] = input;
let command: Command | undefined;

if (serviceName in services) {
  const {commands} = services[serviceName];
  if (commandName in commands) {
    command = new commands[commandName]();
  }
}

command ? command.init() : console.log('No match');