TypeScript 中没有很好的方法来允许具有索引签名的类型具有与索引签名类型不匹配的附加属性。请参阅microsoft/TypeScript#17867 以获取允许索引签名例外的建议,并可能给它一个 ? 以表示对它的支持。不过,目前还没有直接支持。
一种解决方法是使用type intersection 而不是扩展接口:
type SortaHasNumberAndString = { [key: string]: number } & { age: number, name: string };
您基本上是在试图愚弄编译器,因为从技术上讲,这意味着name 属性应该是string 和number 类型,但您希望编译器只注意到string 部分。这在从该类型的值中读取属性时确实有效:
declare const sortaHasNumberAndString: SortaHasNumberAndString;
sortaHasNumberAndString.name; // string, not number
sortaHasNumberAndString.age; // number
sortaHasNumberAndString.numberOfLimbs; // number due to index signature
但在尝试分配给该类型的值时效果不佳:
// error, complains that name is not string & number
const notSoGreat: SortaHasNumberAndString = {
name: "Long John Silver",
age: 43,
numberOfLimbs: 3
}
所以你不得不使用断言或其他技巧:
const notSoGreat = {
name: "Long John Silver",
age: 43,
numberOfLimbs: 3
} as any as SortaHasNumberAndString; // okay now
这意味着你遇到了接受这种类型的函数的麻烦:
declare function acceptSortaHasNumberAndString(x: SortaHasNumberAndString): void;
acceptSortaHasNumberAndString({name: "a", age: 123}); // error!
不理想。
另一种解决方案(我认为更好的解决方案)是允许HasNumber 和HasNumberAndString 在具有数字属性的键中成为generic。这意味着无需担心索引签名。
type HasNumber<K extends keyof any> = Record<K, number>;
type HasNumberAndString<K extends keyof any> = { name: string } & HasNumber<Exclude<K, "name">>;
这使用内置的Record 和Exclude 类型别名来表示HasNumberAndString<K> 应该具有name 类型的string 属性,但所有其他属性都应该是number 类型。如果需要,您可以修改它们以反映不同的约束。让我们看看它是如何工作的:
如果要谈HasNumberAndString类型的具体值,需要在类型中指定键:
const hns: HasNumberAndString<'age'> = {
name: "Harry James Potter",
age: 38
}
这可能不是很好,但在大多数情况下,您可以让 TypeScript 为您推断这些键:
const inferHasNumberAndString =
<T>(x: T & HasNumberAndString<keyof T>): HasNumberAndString<keyof T> => x;
const hns = inferHasNumberAndString({
name: "Harry James Potter",
age: 38
}); // inferred as type HasNumberAndString<"name" | "age">;
上面的帮助函数inferHasNumberAndString 是通用的,它显示了您可以接受HasNumberAndString<K> 类型的值而无需自己强制执行K 的通用方法:
declare function acceptHasNumberAndString<T>(x: T & HasNumberAndString<keyof T>): void;
acceptHasNumberAndString({ name: "Hermione Granger", age: 39 });
希望有所帮助;祝你好运!