好问题。
{a: string}
是不是 {[k:string]: string}
的子集?我们先看下面的代码:
interface T{
a: string;
}
interface K{
[k:string]: string;
}
interface U extends T {
b: number;
}
// 这是合法的操作吧,这里定义的字面量符合 type U,自然可以
// 赋值给 type T 的类型
let foo:U = {a:'hello', b: 1};
let bar:T = foo;
// 而如果 T 类型是 K 类型的子集,那么意味着这个操作也是
// 合法的,但是这明显不符合 K 的类型定义了啊?
let bzz:K = bar;
// TS 如何处理这尴尬局面? type Q 是啥?string 还是 number?
type Q = typeof bzz['b'];
如上,如果规定{a: string}
是 {[k:string]: string}
的子集,那么会出现子类型与父类型冲突的情况。事实上,这种类型定义叫做索引签名(index signature),而官方文档也是有明文规定的,定义了索引签名的接口允许定义其他具名属性,但是类型必须和索引签名相同。即:
interface K{
[key: string]: string;
name: string; // ok
}
interface P extends K {
b: number; // wrong
c: string; // ok
}
显然,{a: string,b:string}
不是 {[k:string]: string}
的子集,因为前者可以有无限的扩展可能,而后者存在扩展限制。而 {[key:string]:any}
就没有问题,本质上它和object
类型是一回事。即题目中的AT
确实是{[key:string]:any}
的子集。
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…