typescript 索引签名的问题

假如我想定义一个对象字面量一定包含isValid类型为boolean的属性,包含其他任意属性,属性名任意,固定为string类型:

type a = {
  isValid: boolean;
  [name: string]: string;
}

这样定义会报错,string不能兼容boolean

type a = 
{
  isValid: boolean;
}&{
  [name: string]: string;
}

这样定义不会报错,但使用的时候还是会报错

let b:a={isValid: false, name: 'name'};

我应该怎么写才能在定义和使用时都不会报错?

阅读 1.5k
1 个回答

没啥好办法,一旦使用了可索引类型(Indexable Type),索引签名和确定属性都必须是相同类型的子集。

所以你只能定义成:

type Foo = {
    isValid: boolean;
    [key: string]: string | boolean;
}

因为对于一个 JS 对象而言,确定属性也是可以通过索引签名形式访问的,即:

let m = obj.isValid;
let n = obj['isValid'];

这二者是等效的,所以它们的类型上一定得是包含和被包含的关系。

只不过这样写有一个比较麻烦的缺点,就是你往后要想取不是 isValid 的属性值,你只能类型断言一次才能当 string 用,就是会多写点儿代码了。


但有一种情况可以区分开,就是用 Symbol,因为 Symbol 的属性你没法直接“点”出来,它和索引签名可以同时存在:

const propSymbol = Symbol('isValid');

type Foo = {
    [propSymbol]: boolean;
    [key: string]: string;
}

const obj: Foo = { [propSymbol]: false, foo: 'bar' }; // ok
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题