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

如何为TypeScript函数的扩展参数准确推断每个Field的类型?

问题

需要为类型函数的每一个扩展参数推断类型,现有字段定义:

type Field<T> = { value: T, name: string }

const field1 = { value: 12, name: 'age' }
const field2 = { value: 'foo', name: 'nickname' }

要将这些字段作为扩展参数传入useForm函数,调用方式如下:

useForm('registration', field1, field2)

尝试使用条件类型推断后,代码如下:

type InferredFields<T> = T extends { value: infer V }[]
  ? Record<string, Field<V>>
  : never

const useForm = <T extends Field<unknown>[]>(name: string, ...args: T) => {
  const fields: InferredFields<T> = args.reduce(
    (res, field) => ({
      ...res,
      [field.name]: field.value,
    }),
    {} as InferredFields<T>,
  )
  return {
    name,
    fields
  }
}

const form = useForm('bar', field1, field2)

但无法根据传入的字段正确区分类型:

type FieldValue<T> = T extends { value: infer V } ? V : never

// 问题:form返回类型为 { fields: Record<string, string | number> }
// 而非具体的键值映射类型,导致以下代码报错
const v1: FieldValue<typeof field1> = form.fields['age'].value // error
const v2: FieldValue<typeof field2> = form.fields['nickname'].value // error

请问如何为每个传入的Field参数正确映射值类型?

解决方案

核心问题在于之前的InferredFields对数组做了整体推断,得到的是联合类型而非每个字段的精确键值映射。需要通过元组遍历逐个提取每个Field的name和value类型,构建精准的键值对类型。

修改后的代码如下:

type Field<T> = { value: T, name: string }

const field1 = { value: 12, name: 'age' } as const
const field2 = { value: 'foo', name: 'nickname' } as const

// 遍历元组T,为每个元素提取name作为键,Field<value类型>作为值
type InferredFields<T extends readonly Field<any>[]> = {
  [K in T[number] as K['name']]: Field<K['value']>
}

const useForm = <T extends readonly Field<any>[]>(name: string, ...args: T) => {
  const fields = args.reduce(
    (res, field) => ({
      ...res,
      [field.name]: field, // 返回完整field对象,匹配Field<T>定义
    }),
    {} as InferredFields<T>,
  )
  return {
    name,
    fields
  }
}

const form = useForm('bar', field1, field2)

type FieldValue<T> = T extends { value: infer V } ? V : never

// 现在类型推断正确,无报错
const v1: FieldValue<typeof field1> = form.fields['age'].value
const v2: FieldValue<typeof field2> = form.fields['nickname'].value

关键修改说明:

  1. as const断言:给字段添加该断言,让TypeScript保留name的字面量类型(如'age'而非泛用的string),这是精确键值映射的前提。
  2. 元组遍历类型:InferredFields改为遍历元组的每个元素,用K['name']作为键,Field<K['value']>作为对应值,确保每个键都是具体字段名,值类型为对应Field的精确类型。
  3. reduce返回值修正:之前错误赋值field.value,现在改为返回完整field对象,匹配Field<T>的结构定义。

修改后,form.fields会被推断为:

{
  age: Field<number>;
  nickname: Field<string>;
}

完美匹配每个字段的value类型,解决类型不匹配的报错问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 23:25:25