Можно ли каким-то образом получить значения в столбцах как тип в столбце данных 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





Вы можете разделить тип объекта строки и тип функции 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?
Я не понимаю, как это могло бы добавить еще одно поле где-либо. Вы просто указываете типы. Никаких дополнительных полей нет.
да, но, скажем, я бы добавил возраст к объекту, const rows = [{ id: 1, firstname: "John", lastname: "Doe", age: 5 }]; можно ли автоматически добавить возраст к типу RowObject без необходимости делать это вручную?
Нет, если вы хотите безопасно использовать эту переменную возраста. Если вас не волнует безопасность типов, вы, конечно, можете ввести объект строки с сопоставленными типами, чтобы его ключами были любые строки (что-то вроде RowObject = {[key: string]: unknown; это отлично работает, если вы используете объект динамически (например, просто отображаете все свойства через Object.keys), но он не совсем подходит для вашего valueFormatter, если вы хотите отображать только некоторые поля (хотя, если это всегда одни и те же поля, вы можете ввести их и ввести так, чтобы остальные ключи могли быть любые строки).
да, думаю, лучше всего объявить отдельный тип :) Большое спасибо за помощь.
Ключевое слово, которое вы ищете, — дженерики. Что-то вроде этого подойдет вам.
// 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
Вопрос не ясен. Вставка вашего кода в коды и ящик дает ошибку. Пожалуйста, отредактируйте это и добавьте ссылку на вопрос codeandbox.io/p/sandbox/…