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

TypeScript动态对象联合键类型设置失效及可选类型疑问

问题描述

我有一个动态设置字段和值的对象:

type PhoneFields = 'deliveryPhoneNumber' | 'pickupPhoneNumber'

(props: {
 phoneField?: PhoneFields
}) {
  const initialValues = {
    [props.phoneField ?? 'deliveryPhoneNumber']: props.address.phone ?? ''
  }
}

我希望为该动态对象设置类型,使其键只能是联合类型PhoneFields中的某一个,因此定义了如下映射类型:

type PhoneValues = {
  [x in PhoneFields]: string
}

但这样会触发TypeScript错误:

Type '{ [x: string]: string; }' is missing the following properties from type 'PhoneValues': deliveryPhoneNumber, pickupPhoneNumber

更新尝试

根据建议将映射类型的键改为可选后,TypeScript错误消失:

type PhoneValues = {
  [x in PhoneFields]?: string
}

但这种设置无法限制非法键,比如使用非PhoneFields的字符串作为键时不会报错:

const initialValues = {
  [props.phoneField ??  'xxxx']: props.address.phone ?? ''
} 

正确解决方案

你需要的是仅包含PhoneFields中单个键的对象类型,而非包含所有键(可选或必选)的类型,具体实现如下:

方式一:手动声明联合类型

直接定义两种单键对象的联合,清晰直观:

type PhoneValues = 
  | { deliveryPhoneNumber: string; pickupPhoneNumber?: never }
  | { pickupPhoneNumber: string; deliveryPhoneNumber?: never };

方式二:通用工具类型自动生成

如果联合类型的成员较多,可以用工具类型自动推导,避免重复代码:

// 通用工具类型:生成仅包含联合类型中单个键的对象类型
type SingleKeyObj<T extends string> = {
  [K in T]: {
    [key in K]: string;
  } & {
    [key in Exclude<T, K>]?: never;
  };
}[T];

// 生成PhoneValues类型
type PhoneValues = SingleKeyObj<PhoneFields>;

为什么之前的方法不生效?

  1. 最初的{ [x in PhoneFields]: string }要求对象必须包含所有PhoneFields的键,但你的动态对象只会有一个键,类型不匹配导致报错。
  2. 改成可选键后,{ [x in PhoneFields]?: string }允许对象有0个或多个合法键,但TypeScript对动态键的场景不会触发额外属性检查,因此非法键也能通过类型校验。

验证效果

使用上述PhoneValues类型后:

  • 合法动态键会被正确识别:
    // 类型匹配,无报错
    const initialValues: PhoneValues = {
      [props.phoneField ?? 'deliveryPhoneNumber']: props.address.phone ?? ''
    };
    
  • 非法键会触发TypeScript错误:
    // 报错:类型"{ xxxx: string; }"不能赋值给类型"PhoneValues"
    const initialValues: PhoneValues = {
      [props.phoneField ?? 'xxxx']: props.address.phone ?? ''
    };
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:50:43