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

如何声明仅含对象可写属性的类型?解决TS代码只读属性赋值报错

问题描述

我正在编写一段简化的TypeScript代码,目的是在父div的X、Y中点创建两个新div。为减少重复代码,我通过循环两次,分别替换width/left和height/top来执行核心逻辑。代码如下:

const parentDiv = document.querySelector('#parentDiv')!;
const clientRect = parentDiv.getBoundingClientRect();

const clientRectProperties: ReadonlyArray<keyof DOMRect> = ['width', 'height'];
const styleProperties: ReadonlyArray<keyof CSSStyleDeclaration> = ['left', 'top'];

for (let a = 0; a < 2; a++) {
  let midpoint = (clientRect[clientRectProperties[a]] as number) / 2
  const newDiv = document.createElement('div');
  newDiv.style[styleProperties[a]] = `${midpoint}px`;
  parentDiv.appendChild(newDiv);
}

但代码第10行出现报错:Cannot assign to 'length' because it is a read-only property. 和 Cannot assign to 'parentRule' because it is a read-only property.。我想知道:如何声明仅包含对象可写属性的类型?同时如何在上述代码中省略只读属性,确保类型正确?

解决方案

1. 报错原因解析

CSSStyleDeclaration接口包含大量只读属性(比如length、parentRule),当用keyof CSSStyleDeclaration作为索引类型时,TypeScript无法确定你访问的是可写属性还是只读属性,因此会抛出赋值权限错误。

2. 定义仅含可写属性的类型工具

可以通过TypeScript条件类型,过滤出对象中所有可写属性的键:

type WritableKeys<T> = {
  [K in keyof T]: T[K] extends Readonly<T[K]> ? never : K;
}[keyof T];

这个类型会遍历目标对象的所有属性,判断属性是否为只读类型,最终只保留可写属性的键名。

3. 修正代码实现

用WritableKeys约束styleProperties的类型,同时明确clientRectProperties的具体属性(确保是DOMRect中的数值类型属性):

const parentDiv = document.querySelector('#parentDiv')!;
const clientRect = parentDiv.getBoundingClientRect();

// 定义可写属性过滤工具类型
type WritableKeys<T> = {
  [K in keyof T]: T[K] extends Readonly<T[K]> ? never : K;
}[keyof T];

// 明确指定为width和height,确保是数值类型属性
const clientRectProperties: ReadonlyArray<'width' | 'height'> = ['width', 'height'];
// 用WritableKeys过滤出CSSStyleDeclaration的可写属性
const styleProperties: ReadonlyArray<WritableKeys<CSSStyleDeclaration>> = ['left', 'top'];

for (let a = 0; a < 2; a++) {
  const midpoint = clientRect[clientRectProperties[a]] / 2;
  const newDiv = document.createElement('div');
  newDiv.style[styleProperties[a]] = `${midpoint}px`;
  parentDiv.appendChild(newDiv);
}

4. 简洁替代写法(属性数量少时)

如果不需要复用类型工具,也可以直接给styleProperties指定具体的可写属性类型,避免宽泛类型导致的错误:

const styleProperties: ReadonlyArray<'left' | 'top'> = ['left', 'top'];

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 11:27:45