Вывести ключ типа из значений другого объекта - PullRequest
0 голосов
/ 07 апреля 2020

У меня есть интерфейсный столбец.

interface column {
  field: string
  label: string
}

Таким образом, строка столбцов будет иметь вид:

const cols = [{
    label: 'First Name',
    field: 'fname',
  },
  {
    label: 'Last Name',
    field: 'lname',
  },
  {
    label: 'Email',
    field: 'email',
  }]

Данные будут представлять собой массив строк данных.

const data:{}[] = [{
fname: 'bob', lname: 'dylan', email: 'db@email.com',
fname: 'van', lname: 'halen', email: 'vh@email.com'
}]

Есть ли способ принудительного применения ключи ie [fname, lname, email] данных должны быть значениями соответствующих столбцов [n] ['field'] ?? Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 07 апреля 2020

Да, вы можете делать это до тех пор, пока вы определяете cols таким образом, чтобы компилятор не расширял свойства field до string. Самый простой способ сделать это с TS3.4 + - это использовать const утверждение :

const cols = [{
  label: 'First Name',
  field: 'fname',
},
{
  label: 'Last Name',
  field: 'lname',
},
{
  label: 'Email',
  field: 'email',
}] as const;

Что as const означает, что cols будет считаться кортежем только для чтения где свойства label и field имеют строковый литерал типов.

Оттуда вы можете создать псевдоним типа, который преобразует набор Column -совместимых значений в тип объекта со свойствами field в качестве ключей. Конечно, нет никакого упоминания о том, каким должен быть тип значения каждого поля, поэтому я предполагаю, что это всегда string:

interface Column {
  field: string
  label: string
};

type StringObjFromColumns<T extends readonly Column[]> =
  { [K in T[number]["field"]]: string }

И тогда мы можем определить ваш тип данных как StringObjFromColumns<typeof cols>:

const data: StringObjFromColumns<typeof cols>[] = [{
  fname: 'bob', lname: 'dylan', email: 'db@email.com',
}, {
  fname: 'van', lname: 'halen', email: 'vh@email.com'
}, {
  fname: 'van', lname: 'morrison', age: 75, email: 'vm@example.com' // error! age is extra
}, {
  fname: 'ted', lname: 'nugent' // error! email is missing
}]

Вы можете увидеть, как он применяет ограничение, согласно которому каждый объект должен иметь эти три поля типа string.

Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

0 голосов
/ 07 апреля 2020

Это невозможно, поскольку типы машинописи применяются во время компиляции, а не во время выполнения. Смотрите мой ответ на этот вопрос , который отвечает на ваш.

0 голосов
/ 07 апреля 2020

Это хитроумно.
Имея

interface Column {
    field: string
    label: string
}

Мы можем определить RowObject и, кроме того, просто для примера, Row, который имеет column свойство и сам row.

interface RowObject {
    [key: string]: string;
}

interface Row {
    cols: Column[];
    object: RowObject;
}

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

const createRowBlueprint = (cols: Column[]): Row => {
    return {
        cols: [...cols],
        object: cols.map(c => c.field)
                    .reduce((prop: RowObject, prev: string) => (prop[prev] = '', prop), {})
    };
};

Я только что определил интерфейс Row для динамического доступа свойства "реального объекта строки", например,

const row = createRowBlueprint(cols);
row.cols.forEach(col => {
    const { field } = col;
    const value = row.object[field];
    console.log(`Field ${field} binded to ${value}`);
});

Учитывая вашу коллекцию columns, это выдает следующее

{
  cols: [
    { label: 'First Name', field: 'fname' },
    { label: 'Last Name', field: 'lname' },
    { label: 'Email', field: 'email' }
  ],
  row: { fname: '', lname: '', email: '' }
}

Field fname binded to
Field lname binded to
Field email binded to

Очевидно, я устанавливаю значение по умолчанию для пустой строки , Но доказательство того, что это работает, состоит в том, что значение, доступное из поля, не undefined.

Наконец, этот подход не является безопасным типом. Но, насколько мне известно, Typescript на данный момент не поддерживает определение типа динамического c во время компиляции ... Так что это сложный обходной путь.

Надеюсь, это поможет.

...