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

TypeScript中如何约束prop参数以访问对象的addressSeq属性

TypeScript类型约束问题:限制函数参数为指定值类型的键

问题场景

现有以下TypeScript代码:

interface IpPatientAddressDto {
  ...
  addressSeq: number;
}

interface IpPatientInfoDto {
  ...
  localAddress: IpPatientAddressDto;
}

const originalPatient:IpPatientInfoDto  = {
  ...
  localAddress:{
     addressSeq: 1
  }
}

const createAddrCollectionObj = (prop: keyof IpPatientInfoDto) => {
      return {
         addressSeq: originalPatient[prop].addressSeq,  // 报错TS2339      
      }
}

const a1 = createAddrCollectionObj('localAddress'); 

运行触发TS2339错误:属性“addressSeq”不存在于类型string | number | Date | IpPatientAddressDto | IpPatientRelationshipDto[]上,因为keyof IpPatientInfoDto包含了很多值类型不是IpPatientAddressDto的键,TypeScript无法确定originalPatient[prop]一定有addressSeq属性。

不想使用额外的取值函数写法:

const get = <T extends keyof ObjType>(key: T): ObjType[T] => {
    return obj[key]
}
let res = get("a"); //"1"

期望实现:

  • 约束prop参数只能是IpPatientInfoDto中值类型为IpPatientAddressDto的键
  • 调用时TypeScript能自动校验传入的键是否合法
  • 函数内部能安全访问addressSeq等IpPatientAddressDto的属性
    目标函数示例:
const createAddrCollectionObj = (prop: keyof IpPatientInfoDto) => {
     const property = originalPatient[prop];
     if (!isIpPatientAddressDto(property,prop)) {
       return null;
     }
     return {
       addressSeq: property.addressSeq,
       patientSeq: property.patientSeq,
       address: patInfo[prop + 'Details'],
       provinceCode: patInfo[prop][0].code,
       provinceName: patInfo[prop][0].name,
       cityCode: patInfo[prop][1].code,
       cityName: patInfo[prop][1].name,
       areaCode: patInfo[prop][2].code,
       areaName: patInfo[prop][2].name,
       zipCode: '', // 邮编
     };
};

解决方案

1. 提取目标键类型

先定义一个类型工具,自动筛选IpPatientInfoDto中值类型为IpPatientAddressDto的键:

// 筛选出IpPatientInfoDto中值类型是IpPatientAddressDto的键
type AddressKeysOfPatient = {
  [K in keyof IpPatientInfoDto]: IpPatientInfoDto[K] extends IpPatientAddressDto ? K : never
}[keyof IpPatientInfoDto];

这个类型会遍历IpPatientInfoDto的所有键,只保留符合条件的键(比如你的localAddress)。

2. 约束函数参数

把prop的类型从keyof IpPatientInfoDto替换为AddressKeysOfPatient,这样调用时只能传入合法的键,非法键会直接编译报错:

const createAddrCollectionObj = (prop: AddressKeysOfPatient) => {
  const property = originalPatient[prop];
  // 此时TypeScript已推断property为IpPatientAddressDto,可直接访问addressSeq
  return {
    addressSeq: property.addressSeq,
    patientSeq: property.patientSeq,
    // 其他属性...
  };
};

// 合法调用
const a1 = createAddrCollectionObj('localAddress'); 
// 非法调用会直接编译报错(假设IpPatientInfoDto有name: string字段)
// const a2 = createAddrCollectionObj('name'); 

3. 配合类型守卫处理可选/联合类型

如果IpPatientInfoDto中部分键的类型是IpPatientAddressDto | undefined这类联合类型,需要添加类型守卫确认类型:

// 实现类型守卫函数
function isIpPatientAddressDto(obj: unknown): obj is IpPatientAddressDto {
  return typeof obj === 'object' && obj !== null && 'addressSeq' in obj;
}

// 函数中使用类型守卫
const createAddrCollectionObj = (prop: AddressKeysOfPatient) => {
  const property = originalPatient[prop];
  if (!isIpPatientAddressDto(property)) {
    return null;
  }
  return {
    addressSeq: property.addressSeq,
    patientSeq: property.patientSeq,
    // 其他属性...
  };
};

4. 处理字符串拼接的键(如prop + 'Details')

如果需要访问patInfo[prop + 'Details']这类拼接后的键,需要扩展类型工具确保拼接后的键合法:

// 假设patInfo的类型为PatientDetailsInfo
type AddressKeysWithDetails = {
  [K in keyof IpPatientInfoDto]: 
    IpPatientInfoDto[K] extends IpPatientAddressDto 
    ? `${K}Details` extends keyof PatientDetailsInfo ? K : never 
    : never
}[keyof IpPatientInfoDto];

// 使用新的类型约束prop
const createAddrCollectionObj = (prop: AddressKeysWithDetails) => {
  const property = originalPatient[prop];
  if (!isIpPatientAddressDto(property)) {
    return null;
  }
  return {
    addressSeq: property.addressSeq,
    address: patInfo[`${prop}Details`], // TypeScript可识别此键合法
    // 其他地址相关属性...
  };
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 12:58:19