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

如何通过TypeScript类型约束rows包含fieldNames指定的键

如何约束TypeScript Table类型中rows元素必须包含fieldNames指定的键

我当前的Table类型定义如下:

type Table = {
  fieldNames: {
    id: string,
    children?: string
  },
  rows: Array<(
    Record<string, any> & {
      label: string,
      ...
    }
  )>
};

但这个类型无法约束rows的元素必须包含fieldNames.id和fieldNames.children值对应的键,即使缺少这些键TypeScript也不会报错。需要修改类型定义,实现rows元素必须包含fieldNames指定的键的类型约束,同时保留自定义键名的灵活性。

正确示例(无报错)

const table = {
  fieldNames: {
    id: "uuid",
    children: "objects"
  },
  rows: [
    {
      uuid: 1,
      objects: 2,
      label: "示例行"
    }
  ]
};

自定义键名的正确示例

const table = {
  fieldNames: {
    id: "MY_CUSTOM_ID_KEY",
    children: "MY_CUSTOM_CHILDREN_KEY"
  },
  rows: [
    {
      MY_CUSTOM_ID_KEY: "SOMETHING VERY GOOD",
      MY_CUSTOM_CHILDREN_KEY: "SOMETHING, DO NOT CARE",
      label: "自定义键行"
    }
  ]
};

错误示例(应报错)

const table = {
  fieldNames: {
    id: "uuid",
    children: "objects"
  },
  rows: [
    {
      id: 1,
      children: 2,
      label: "错误行"
    }
  ]
};

解决方案:使用泛型动态约束键名

通过泛型捕获fieldNames的具体类型,再利用索引访问类型动态生成rows元素必须包含的键约束:

// 定义泛型Table类型
type Table<TFieldNames extends { id: string; children?: string }> = {
  fieldNames: TFieldNames;
  rows: Array<
    // 必须包含fieldNames.id指定的键
    Record<TFieldNames["id"], any> &
    // 如果fieldNames.children存在,则必须包含对应的键
    (TFieldNames["children"] extends string ? Record<TFieldNames["children"], any> : {}) &
    // 保留原类型中的label字段要求
    { label: string }
  >;
};

// 辅助函数用于自动推断泛型类型
function createTable<T extends { id: string; children?: string }>(table: Table<T>) {
  return table;
}

使用方式

用createTable包裹对象字面量,TypeScript会自动推断fieldNames的键值,并约束rows元素必须包含对应键:

合法使用

// 带children的情况
const validTable = createTable({
  fieldNames: { id: "uuid", children: "objects" },
  rows: [
    { uuid: 1, objects: [{}], label: "有效行1" },
    { uuid: 2, objects: [], label: "有效行2" }
  ]
});

// 不带children的情况
const validTableWithoutChildren = createTable({
  fieldNames: { id: "uuid" },
  rows: [
    { uuid: 1, label: "有效行" }
  ]
});

非法使用(TypeScript会报错)

const invalidTable = createTable({
  fieldNames: { id: "uuid", children: "objects" },
  rows: [
    // 报错:缺少uuid和objects键
    { id: 1, children: [], label: "错误行" }
  ]
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 13:36:02