通过 for...in 等方式动态添加属性,Typescript 无法识别的问题?

请教一个 Typescript 动态添加属性的问题。

我们知道 JS 里可任意添加属性且无类型限制。假设有以下场景:

const base = {
  age: 20,
  skill: 'TS',
}

const person = {
  name: 'Frankie',
}

// 给 person 动态添加属性
for (const key in base) {
  if (Object.prototype.hasOwnProperty.call(base, key)) {
    person[key] = 'any value' // string、number、function etc.
  }
}

// 请问有什么办法,可以让 TS 自动识别 for...in 动态添加的属性?
// 比如 person.age 可识别前面动态赋值的 'any value' 对应类型。
console.log(person.age)

疑问已在示例中提出。

假设项目中 base 是会随着业务迭代而发生变化的,我希望在键入 person.xxx 的时候,TS 会根据 for...in 动态添加的属性,自动推断出对应的类型。

TS 写得不多,所以请教下各位大佬,谢谢!

阅读 2.4k
5 个回答

给 person 声明类型

const person: {
  name: string;
  age: number;
  skill: string;
} = {
  name: '',
  age: 0,
  skill: '',
}

可以这样

const base = {
  age: 20,
  skill: 'TS',
  tt: 'x',
  gg: '2'
}

const person: Record<keyof typeof base, any> = {
  age: 'Frankie',
  skill: 'cc',
  tt: 's',
  gg: 'l'
}

但是你不能动态往 person 中添加属性,因为在你声明类型之后person的类型就已经确定了,所以初始化person的时候就需要有base的所有属性,在线demo

  1. 设计类型系统的目标,就是在开发阶段对代码进行限制,避免过分灵活产生各种问题。所以原则上,不应该乱来,所有将来会添加到对象上的字段,都应该在初始时就声明。
  2. 所以应该先给 person 设计类型,然后在其它代码里使用,即:
type Person = {
  name: string; // 必填项
  age?: number; // 加问号,选填项
  skill?: string[]; // 选填项,字符串组成的数组
}

无法实现。只能提前给person添加类型,既然业务迭代需要改js,那对应的ts也得改。

根本原因是:ts是在预处理阶段转成js再编译运行的,管不了js运行时的东西。

可以扩展person的类型,例如:

interface Base {
  age:number
  skill:string
}

interface Person extends Base {
  name:string
}

const person:Partial<Person> = {
  name: 'Frankie',
}

假设你base的类型是接口是BASE.

interface BASE {
    age: number;
    skill: string[];
}

你给person添加属性后想要识别到, 那么让你的这个person的类型和BASE进行合并即可。假设为Person

interface Person extends BASE {
    name: string;
}

效果如图,属性都可以识别和提示

image.png

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题