← 中文资源

简体中文版本

TypeScript — TS2345 参数类型不可赋值

通过阅读完整类型、收窄联合类型、处理可选属性并避免不安全 any 断言,诊断并修复 TypeScript TS2345 错误。

阅读英文原文

读第二个类型,而不只是第一个

TS2345 同时列出赋值两侧的类型。多数开发者只读第一个类型,认出自己的值就停下。有用信息在目标类型里:哪个属性是必需的、允许哪个字面量、参数是否接受联合类型。编译器在第一个不兼容处停止,所以先修这个属性再重跑,不要猜其余部分。

type Status = 'draft' | 'published';

function setStatus(status: Status) {}

const value = 'draft'; // 推断为 string,而不是 'draft'
setStatus(value); // TS2345

变量被推断为 string,因为 let 和对象属性会拓宽字面量。const value = 'draft' as const 或显式标注 Status 可以保留字面量。对对象字面量,satisfies 会检查形状而不拓宽值:

const config = { status: 'draft' } satisfies { status: Status };
setStatus(config.status); // OK

调用前先收窄

参数是联合类型时,运行时检查同时也是编译期收窄:

type Result = { ok: true; value: string } | { ok: false; error: Error };

function handle(result: Result) {
  if (result.ok) {
    consume(result.value); // 收窄到成功分支
  }
}

result as { value: string } 这样的断言能编译,但不会在运行时检查判别字段。优先使用守卫或可辨识联合。如果数据来自 JSON.parse,断言尤其危险:解析结果是 any,编译器无法验证。

契约错误时修签名

有时调用点正确,而参数过窄。如果函数接受 string[],但调用方传只读数组,就改成 readonly string[]。如果某个可选字段在某个流程中总会提供,拆分函数或使用重载。不要为了消错给参数加 any,那会移除所有调用方的检查。

在相同配置下验证

编辑器诊断可能与 CI 不同,如果它们使用不同的 tsconfig 或 TypeScript 版本。运行 CI 使用的同一条 tsc --noEmit,并确认修复没有通过 skipLibCheck 或宽泛 exclude 压制错误。不同配置下的本地干净构建不是证据。