TypeScript中使用Interface定义对象时如何获取其实际键?
问题解答
当你用IAddress接口直接标注对象变量时,无法直接获取对象的实际键名类型,原因是:
IAddress定义了[key: string]: IPerson的索引签名,TypeScript会将变量的类型收窄为IAddress,此时typeof personInAddressObj的类型就是IAddress,而keyof IAddress的结果是string,自然无法得到具体的"someAddress1" | "someAddress2"。- 去掉接口标注后,TypeScript会自动推断对象的字面量类型,保留所有具体键名,因此
keyof能拿到期望的联合类型。
解决方案:兼顾类型约束与具体键名保留
如果你既要让对象符合IAddress的类型规则,又要保留实际键名的类型信息,可以用以下两种方式:
1. 先推断对象类型,再验证约束
先创建带as const的对象让TypeScript推断具体类型,再通过类型检查确保它符合IAddress的要求:
interface IPerson { name: string; } interface IAddress { [key: string]: IPerson; } // 先创建对象,保留具体键名类型 const personInAddressObj = { someAddress1: { name: 'John', }, someAddress2: { name: 'Jacob', } } as const; // 验证对象是否符合IAddress类型,不符合会触发编译错误 type _VerifyAddress = typeof personInAddressObj extends IAddress ? true : false; type Keys = keyof typeof personInAddressObj; // "someAddress1" | "someAddress2"
2. 使用泛型函数约束类型
通过泛型函数接收对象,既约束对象符合IAddress,又返回对象的具体字面量类型:
interface IPerson { name: string; } interface IAddress { [key: string]: IPerson; } function createAddress<T extends IAddress>(address: T): T { return address; } const personInAddressObj = createAddress({ someAddress1: { name: 'John', }, someAddress2: { name: 'Jacob', } } as const); type Keys = keyof typeof personInAddressObj; // "someAddress1" | "someAddress2"
这两种方式都能在确保对象类型合法的前提下,保留实际键名的类型信息,满足你的需求。
内容的提问来源于stack exchange,提问作者Kustemit
相关产品推荐
相关产品推荐

