Есть ли способ получить ключ собственного типа в машинописном тексте?

Можно ли каким-то образом получить значения в столбцах как тип в столбце данных valueFormatter? Итак, если бы я ввел идентификатор, имя и фамилию в виде столбцов, как показано ниже, я бы получил их только как тип функции valueformatter?

Цель состоит в том, чтобы получить столбцы (id, имя и фамилия) как тип в формате значения.

import "./App.css";

interface TableColumn {
  name: string;
  // TODO: make this type same as type of the keys in one of the objects in rows
  valueFormatter?: (datacolumn: {
    id: number;
    firstname: string;
    lastname: string;
  }) => void;
}

interface TableProps {
  columns: TableColumn[];
  rows: any[];
}

const Table = ({ columns, rows }: TableProps) => {
  return (
    <div>
      <div style = {{ display: "flex" }}>
        {rows.map((row, index) => (
          <div key = {`row-${index}`} style = {{ display: "inline-flex" }}>
            {columns.map((col) => (
              <div
                key = {col.name}
                style = {{ padding: "1rem", border: "1px solid white" }}
              >
                {col.valueFormatter ? col.valueFormatter(row) : row[col.name]}
              </div>
            ))}
          </div>
        ))}
      </div>
    </div>
  );
};

function App() {
  const columns = [
    {
      name: "id",
      valueFormatter: (row) => {
        return row.firstname + "some value";
      },
    },
    { name: "firstname" },
    { name: "lastname" },
  ];
  const rows = [{ id: 1, firstname: "John", lastname: "Doe" }];

  return (
    <div className = "App">
      <Table columns = {columns} rows = {rows} />
    </div>
  );
}

export default App;



https://codesandbox.io/p/sandbox/sleepy-thunder-23vwdh?file=%2Fsrc%2FApp.tsx%3A1%2C1-48%2C1

Вопрос не ясен. Вставка вашего кода в коды и ящик дает ошибку. Пожалуйста, отредактируйте это и добавьте ссылку на вопрос codeandbox.io/p/sandbox/…

Tushar Shahi 25.09.2023 19:14
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
1
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете разделить тип объекта строки и тип функции valueFormatter на отдельные переменные типа, а затем использовать их как в TableColumn, так и в фактической реализации valueFormatter.

type RowObject = {
  id: number;
  firstname: string;
  lastname: string;
}

// Note that you have the return type for the value formatter marked as void
// but you return a string from it, so used that here.
type ValueFormatter = (rowObject: RowObject) => string;

interface TableColumn {
  name: string;
  valueFormatter?: ValueFormatter
}

// then in App.tsx:

// Type the variable itself here
const columns: TableColumn[] = [
  {
    name: "id",
    // No need to type the row here explicitly as the columns variable itself
    // is typed so TypeScript also knows the type of the row variable from that
    valueFormatter: (row) => {
      return row.firstname + "some value";
    },
  },
  { name: "firstname" },
  { name: "lastname" },
];

// Type also this variable for safety
const rows:: RowObject[] = [{ id: 1, firstname: "John", lastname: "Doe" }];

Затем вы также можете правильно ввести реквизит rows в компоненте Table.

да, это могло бы сработать, но, скажем, я бы добавил еще одно поле в столбец/тип в объект строки. можно ли автоматически сгенерировать тип RowObject?

Arvid W 25.09.2023 20:12

Я не понимаю, как это могло бы добавить еще одно поле где-либо. Вы просто указываете типы. Никаких дополнительных полей нет.

tuomokar 25.09.2023 20:19

да, но, скажем, я бы добавил возраст к объекту, const rows = [{ id: 1, firstname: "John", lastname: "Doe", age: 5 }]; можно ли автоматически добавить возраст к типу RowObject без необходимости делать это вручную?

Arvid W 25.09.2023 20:23

Нет, если вы хотите безопасно использовать эту переменную возраста. Если вас не волнует безопасность типов, вы, конечно, можете ввести объект строки с сопоставленными типами, чтобы его ключами были любые строки (что-то вроде RowObject = {[key: string]: unknown; это отлично работает, если вы используете объект динамически (например, просто отображаете все свойства через Object.keys), но он не совсем подходит для вашего valueFormatter, если вы хотите отображать только некоторые поля (хотя, если это всегда одни и те же поля, вы можете ввести их и ввести так, чтобы остальные ключи могли быть любые строки).

tuomokar 25.09.2023 20:29

да, думаю, лучше всего объявить отдельный тип :) Большое спасибо за помощь.

Arvid W 25.09.2023 20:33
Ответ принят как подходящий

Ключевое слово, которое вы ищете, — дженерики. Что-то вроде этого подойдет вам.

// takes generic Row
type TableColumn<Row> = {
  name: keyof Row & string;
  valueFormatter?: (datacolumn: Row) => string;
};

// takes generic Row and passes it to TableColumn.
type TableProps<Row> = {
  columns: TableColumn<Row>[];
  rows: Row[];
};

// takes generic Row but this time it extends Record<string, any>
// instead of any, you can specify string | number etc...
// you can extend in the other generic Row implementations above too. 
// It would make sense if you did actually. But not necessary.
const Table = <Row extends Record<string, any>>({
  columns,
  rows,
}: TableProps<Row>) => {
  return (
    <div>
      <div style = {{ display: "flex" }}>
        {rows.map((row, index) => (
          <div key = {`row-${index}`} style = {{ display: "inline-flex" }}>
            {columns.map((col) => (
              <div
                key = {col.name}
                style = {{ padding: "1rem", border: "1px solid white" }}
              >
                {col.valueFormatter ? col.valueFormatter(row) : row[col.name]}
              </div>
            ))}
          </div>
        ))}
      </div>
    </div>
  );
};

function App() {

  // define a Row that you will use
  type Row = {
    id: number;
    firstname: string;
    lastname: string;
  };

  // use TableColumn<Row> type so that typescript holds your hand while writing the columns.
  const columns: TableColumn<Row>[] = [
    {
      name: "id",
      valueFormatter: (row) => {
        // you get nice editor support for row here.
        return row.firstname + "some value";
      },
    },
    { name: "firstname" },
    { name: "lastname" },
  ];

  // You can use Row[] here as well.
  const rows: Row[] = [{ id: 1, firstname: "John", lastname: "Doe" }];

  return (
    <div className = "App">
      <Table columns = {columns} rows = {rows} />
    </div>
  );
}

export default App;

Таким образом, вы можете отделить компонент «Таблица» и использовать его с любым количеством типов строк. экспортируйте TableColumn и TableProps, чтобы вы могли использовать их в своих компонентах, которые будут использовать компонент Table.

Да! Это именно то, что я искал. Большое спасибо вам и туомокару за помощь :D

Arvid W 25.09.2023 20:29

Другие вопросы по теме