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

如何在TypeScript中正确映射深层嵌套键与对应值

问题原因

当你将类型移入泛型后,TypeScript的结构类型兼容性允许FIELDS包含额外属性。FIELDS extends Partial<MatchFormField<STATE>>仅要求FIELDS的属性值符合FormField结构,但未限制键必须是Path<STATE>的成员。TypeScript会推断FIELDS为包含未知字段的类型,而非自动收窄到合法字段集合。

解决方案

需要明确约束FIELDS的键只能是Path<STATE>的子集,以下两种方案均可实现:

方案1:移除独立的FIELDS泛型参数

直接将fields的类型设为Partial<MatchFormField<STATE>>,让TypeScript严格检查键的合法性:

import type { Path, PathValue } from '@clickbar/dot-diver'

type FormField<VALUE> = { initialValue: VALUE }
type MatchFormField<STATE> = { [FIELD in Path<STATE>]-?: FormField<PathValue<STATE, FIELD>> }

export type FormConfig<STATE> = {
  id: string
  initialValues: STATE
  fields?: Partial<MatchFormField<STATE>>
}

declare function createForm<STATE>(config: FormConfig<STATE>): void

createForm({
  id: 'test-form',
  initialValues: {
    uid: 'abcd',
    profile: {
      name: 'Mark',
      age: 44,
    }
  },
  fields: {
    uid: { initialValue: '00000' },
    'profile.age': { initialValue: 99 },

    // 现在会被正确标记为无效
    unknownField: { initialValue: 'matteo' }, 
  },
})

方案2:保留FIELDS泛型并约束键类型

如果需要保留FIELDS的具体类型(比如在返回值中使用),可以通过泛型约束明确FIELDS的键必须是Path<STATE>的成员:

import type { Path, PathValue } from '@clickbar/dot-diver'

type FormField<VALUE> = { initialValue: VALUE }
type MatchFormField<STATE> = { [FIELD in Path<STATE>]-?: FormField<PathValue<STATE, FIELD>> }

export type FormConfig<STATE, FIELDS extends Record<keyof FIELDS, Path<STATE>>> = {
  id: string
  initialValues: STATE
  fields?: FIELDS & Partial<MatchFormField<STATE>>
}

declare function createForm<
  STATE,
  FIELDS extends Record<keyof FIELDS, Path<STATE>>
>(config: FormConfig<STATE, FIELDS>): void

createForm({
  id: 'test-form',
  initialValues: {
    uid: 'abcd',
    profile: {
      name: 'Mark',
      age: 44,
    }
  },
  fields: {
    uid: { initialValue: '00000' },
    'profile.age': { initialValue: 99 },

    // 现在会被正确标记为无效
    unknownField: { initialValue: 'matteo' }, 
  },
})
效果验证

两种方案都会让unknownField被TypeScript正确标记为无效,因为fields的键被严格限制为initialValues中存在的嵌套路径(通过Path<STATE>约束)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 21:47:38