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

TypeScript如何获取对象的非只读属性键 避免只读属性赋值报错

TypeScript 筛选非只读属性键实现

首先定义两个工具类型:

// 辅助工具:严格判断两个类型是否完全等价
type IfEquals<X, Y, A = X, B = never> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? A : B

// 提取目标类型的所有非只读属性键
type WritableKeys<T> = {
  [K in keyof T]: IfEquals<
    { [P in K]: T[K] },
    { -readonly [P in K]: T[K] },
    K,
    never
  >
}[keyof T]

实现逻辑

  • 对类型T的每一个属性键K,分别构造两个只有readonly修饰符差异的同结构类型
  • 如果两个类型完全等价,说明原属性本身没有readonly修饰,保留该键;否则说明是只读属性,过滤掉
  • 最终返回所有非只读属性键的联合类型

业务代码改造

将你的代码中propertiesToClear的参数类型从Array<keyof Test>替换为Array<WritableKeys<Test>>即可:

interface Test {
    readonly a: string;
    b: string;
}

type IfEquals<X, Y, A = X, B = never> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? A : B

type WritableKeys<T> = {
  [K in keyof T]: IfEquals<
    { [P in K]: T[K] },
    { -readonly [P in K]: T[K] },
    K,
    never
  >
}[keyof T]

const clearProperties = (propertiesToClear: Array<WritableKeys<Test>>, onObject: Test): Test => {    
    // 注意:原代码for in遍历数组拿到的是下标,需改为for of拿到属性名
    for (const key of propertiesToClear) {
        onObject[key]  = ""; // 不会再触发只读属性赋值报错
    }
    return onObject;
}

// 调用测试
clearProperties(['b'], {a: 'test', b: 'test'}) // 编译正常
clearProperties(['a'], {a: 'test', b: 'test'}) // 编译直接报错:a 不属于允许的属性值

这个方案可以在调用阶段就拦截只读属性的传入,从类型层面完全规避赋值报错的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 11:51:03