字面量类型严格检测方面的知识,才能理解奇怪的现象interface IIterator {
// 索引签名
[index: string]: number;
// 该属性受索引签名约束,
// 如果返回其他类型,则会报错
length: number;
}
type IteratorType = {
[index: number]: string;
// 这里index为number,这里没报错的原因是,数组默认原型包含length字段
length: number;
};
const test1: IIterator = {
age: 23,
price: 18.9,
length: 2,
};
const test2: IteratorType = ["1", "2"];
原文(官方文档):JavaScript will actually convert that to a
stringbefore indexing into an object. That means that indexing with100(anumber) is the same thing as indexing with"100"(astring), so the two need to be consistent.文档链接:https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures
翻译:js实际上会在索引到对象之前将其转换为字符串,也就死说100(number)进行索引与"100"(string)进行索引是一回事,因此两者(两种索引签名)需要保持一致。
class Animal {
constructor(public age: number) {}
}
class Pig extends Animal {
constructor(public name: string, age: number) {
super(age);
}
}
interface IBothIndexIterator {
[index: number]: Pig; // 索引类型为number的返回值类型,必须为必须为Animal or Animal的子类型
[index: string]: Animal;
}
// ❌ 错误演示
interface IErrorBothIndexIterator {
[index: number]: object; // ❌ 索引类型为number的返回值类型不是Animal,反而是Animal的父类型
[index: string]: Animal;
}
// 索引签名数组问题 - [index: string]: string
interface IIndex {
[index: string]: string;
}
// 尝试将arr改为非fresh新鲜的,扩展字面量
const arr = ["1", "2"];
// ❌ 字面量严格类型检测,索引默认为number无法通过
const arr1: IIndex = arr;
// ❌ 同上错误
const arr2: IIndex = ["1", "2"];
// ✅ 符合类型
const obj1: IIndex = {
"0": "0",
"2": "1",
};
// ✅ 符合类型,不要以为写的0就是个number了,实际上object的key都是string类型,所以这里通过
const obj2: IIndex = {
0: "0",
1: "1",
};
这里都很好理解,我要讲的是下面这个现象,类型检测居然不会检测索引类型了?🤔
奇怪的现象🤔// 奇怪的现象:[index: string]: any;
interface IIndexInattentive {
[index: string]: any;
}
// ✅ 都通过🤔
const arr1: IIndexInattentive = ["1", "2"];
const obj1: IIndexInattentive = {
0: "0",
1: "1",
};
这里就仿佛根本没有对索引进行检索
论点:是否因为字面量包含了函数等方法,导致不通过呢?❌// 奇怪的现象论点:字面量隐式包含函数类型 ❌
interface IIndexSigWithFunc {
[index: string]: string | ((...args: any[]) => any);
}
// ❌
const arr1: IIndexSigWithFunc = ["1", "2"];
// ✅
const obj1: IIndexSigWithFunc = {
"0": "0",
"2": "1",
"3"() {},
};
I think that's a good assumption, I can't think of a scenario where the target type would want to mandate an index signature explicitly. The index signature of type of any or empty object would then always signify a loose check, making the above code pass without error - correct?
翻译:我认为这是一个很好的假设,我想不出目标类型想要明确要求索引签名的场景。然后,
any类型或空对象的索引签名将始终表示松散的检查,从而使上述代码无错误地通过
any类型空对象的索引签名默认为宽松// 奇怪的现象:[index: string]: any; 宽松索引签名
// 方式一:any触发条件的宽松索引签名
interface IIndexInattentive {
[index: number]: any;
}
// ✅ 你会发现它们不再检查索引类型,完全不检查了
const arr1: IIndexInattentive = ["1", "2"];
const obj1: IIndexInattentive = {
0: "0",
1: "1",
[Symbol("2")]: () => {},
};
// 方式二:空对象触发条件的索引签名
// ✅ 都通过
let obj3: {} = ["1", "2", 3, true];
obj3 = {
k: "v",
"0": 0,
1: "1",
// 甚至symbol都能通过
[Symbol("3")]: () => {},
};
总结:宽松索引签名,是为了特定场景,如框架的类型定义,不用因为过于严格,而导致类型定义起来特别麻烦