Не удается получить доступ к глубоким свойствам/значениям объекта

#javascript #typescript #types #deno

Вопрос:

Итак, ниже приведен мой пример кода тестирования для внедрения в более широкое решение. Я создал объект «услуги», каждое свойство-это имя службы, значение которого является объектом службы. Каждый объект службы содержит свойство «команды», значение которого является объектом команд (classe).

Эти команды выполняются через интерфейс командной строки, который всегда возвращает строку, которая затем разделяется. индекс 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 as не установлен в никогда. Которого, как я понимаю, commands не может быть a , И b поэтому ключ должен быть never , но как мне с этим работать?

Комментарии:

1. ваша цель, чтобы команды имели произвольные строки в качестве ключей или, в частности, a, b,…? команды ie: {[key: string]: A|B} или {a: A} | {b: B}

Ответ №1:

Вам просто нужно определить тип для вашего services объекта, как в приведенном ниже рефакторе. Если вы хотите ограничить ключи для любой части структуры, вы можете просто string заменить их своим объединением/перечислением/и т. Д.

Примечание.Я предоставил замену Deno API-интерфейсам пространства имен, используемым в вашем коде, чтобы вы могли запустить пример игровой площадки непосредственно в своем браузере.

Ссылка на игровую площадку TS

 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');
 

Комментарии:

1. Потрясающе, спасибо за это. Это не была работа по копированию/вставке, но в конце концов ей удалось заставить ее работать с вашим примером в качестве ссылки.