Typescript проверяет все значения объекта при извлечении ключей как объединение - PullRequest
0 голосов
/ 10 марта 2020

Я пытаюсь проверить значения литерала объекта и одновременно создать объединение всех ключей в качестве типа параметра для функции.

interface PathValue {
    prop1: string;
    prop2?: number;
}

interface PathDeclaration {
    [key: string]: PathValue;
}

const allPaths: PathDeclaration = {
    'one': {prop1: 'foo'},
    'two': {prop1: 'bar', prop2: 2},
}


function getItem(path: Extract<keyof typeof allPaths, string>) {
    return allPaths[path];
}

Проблема в этом примере заключается в том, что поскольку PathDeclaration является типом allPaths, а его ключи являются просто обобщенными c строками, мой параметр path не может больше выводить ключи из литерала объекта.

Единственное решение, которое я могу придумать, это чтобы объявить все ключи в отдельном интерфейсе (дублирующий код) или вместо ввода allPaths, я мог бы удалить PathDeclaration и просто ввести каждое значение, например 'one': <PathValue> {prop1: 'foo'},, что не является очень элегантным решением. Есть ли способ проверки всего объекта allPaths И создания типа объединения ключей из литерала объекта?

1 Ответ

1 голос
/ 10 марта 2020

Вы хотите инициализировать const allPaths с помощью обобщенной функции c, чтобы 1) добавить ограничение типа PathDeclaration и 2) let TS вывод данный объект буквальный тип автоматически. Только функции могут сделать это за один шаг.

const createPaths = <T extends PathDeclaration>(pd: T) => pd

const allPaths = createPaths({
  'one': { prop1: 'foo' },
  'two': { prop1: 'bar', prop2: 2 },
})
/* 
{
  one: { prop1: string; };
  two: { prop1: string; prop2: number; };
}
 */

Выше будут ловить ошибки:

const allPathsError = createPaths({
  'one': { prop3: 'foo' }, // error
  'two': { prop1: 'bar', prop2: "bar" }, // error
})

И вывести все ключи:

// path: "one" | "two"
function getItem(path: Extract<keyof typeof allPathsInline, string>) {
  return allPathsInline[path];
}

Это тоже один из немногих случаев, когда я хотел бы использовать IIFE , чтобы сделать вещи простыми:

const allPathsInline = (<T extends PathDeclaration>(pd: T) => pd)({
  'one': { prop1: 'foo' },
  'two': { prop1: 'bar', prop2: 2 },
})

Пример кода

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...