You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript获取自身类型key及表格列类型约束技术问询

问题

  1. 在TypeScript中,有没有办法获取自身类型的keyof?
  2. 能不能把表格columns中的字段值作为valueFormatter的参数类型?比如传入id、firstname、lastname作为列时,让valueFormatter函数的参数只包含这些键对应的类型,目标是让columns中的字段决定valueFormatter的参数类型。相关代码示例如下:
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;

回答

1. 获取自身类型的keyof

完全可以,具体分几种场景实现:

  • 类内部获取自身键类型:用keyof this直接指向当前类实例的所有键
class User {
  id: number;
  name: string;
  getValidKeys(): Array<keyof this> {
    return Object.keys(this) as Array<keyof this>;
  }
}
  • 接口/类型别名内部引用:直接使用keyof 自身类型名
interface Product {
  id: number;
  price: number;
  allowedKeys: Array<keyof Product>;
}
  • 泛型函数中获取参数自身键类型:通过泛型T推断参数类型,再取keyof T
function getObjectKeys<T>(obj: T): Array<keyof T> {
  return Object.keys(obj) as Array<keyof T>;
}

2. 让columns字段约束valueFormatter的参数类型

核心是用泛型关联行数据类型与列配置,让列名必须匹配行数据的键,同时valueFormatter的参数严格对应行数据类型。修改后的代码如下:

import "./App.css";

// 泛型T代表单行数据的类型,约束列名必须是T的键
type TableColumn<T> = {
  name: keyof T;
  valueFormatter?: (row: T) => React.ReactNode;
};

// 表格Props用泛型T关联列和行的类型
interface TableProps<T> {
  columns: TableColumn<T>[];
  rows: T[];
}

// 表格组件接收泛型T,确保行是对象类型
const Table = <T extends Record<string, unknown>>({ columns, rows }: TableProps<T>) => {
  return (
    <div>
      <div style={{ display: "flex" }}>
        {rows.map((row, index) => (
          <div key={`row-${index}`} style={{ display: "inline-flex" }}>
            {columns.map((col) => (
              <div
                key={`${index}-${String(col.name)}`}
                style={{ padding: "1rem", border: "1px solid #ccc" }}
              >
                {col.valueFormatter ? col.valueFormatter(row) : row[col.name]}
              </div>
            ))}
          </div>
        ))}
      </div>
    </div>
  );
};

function App() {
  // 显式声明行数据类型,让列配置和行数据强关联
  type RowType = {
    id: number;
    firstname: string;
    lastname: string;
  };

  const columns: TableColumn<RowType>[] = [
    {
      name: "id",
      valueFormatter: (row) => {
        // 此处row被严格约束为RowType,只能访问id、firstname、lastname
        return `${row.firstname} 的ID是 ${row.id}`;
      },
    },
    { name: "firstname" },
    { name: "lastname" },
  ];

  const rows: RowType[] = [{ id: 1, firstname: "John", lastname: "Doe" }];

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

export default App;

关键改动说明:

  • 给TableColumn和TableProps添加泛型T,让列配置与行数据类型绑定
  • TableColumn的name字段被约束为keyof T,确保列名必须是行数据中存在的键
  • valueFormatter的参数类型直接使用T,函数内部只能访问行数据的合法属性,避免类型错误
  • 显式声明RowType后,TypeScript会自动校验列名和valueFormatter的参数使用,提供准确的类型提示

内容的提问来源于stack exchange,提问作者Arvid W

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 22:23:19