Typescript 更改对象上属性的位置后获取正确的类型信息

Typescript 更改对象上属性的位置后获取正确的类型信息,typescript,Typescript,我有一个嵌套的选项对象,它被一些代码修改并将某些属性上移一级 我正努力在这个场景中获得适当的typescript支持 函数createStore(选项){ //做事 } //给定 常量选项={ 国家:{}, 模块:{ 建筑物:{ 国家:{}, 模块:{ 学校:{ 国家:{} }, 咖啡厅:{ 国家:{} } } } } }; //无效的类型定义 类型ObjectInfer=T扩展{modules:infera}?A:T; 类型Store={[P in keyof T]:ObjectInfer};

我有一个嵌套的选项对象,它被一些代码修改并将某些属性上移一级

我正努力在这个场景中获得适当的typescript支持

函数createStore(选项){
//做事
}
//给定
常量选项={
国家:{},
模块:{
建筑物:{
国家:{},
模块:{
学校:{
国家:{}
},
咖啡厅:{
国家:{}
}
}
}
}
};
//无效的类型定义
类型ObjectInfer=T扩展{modules:infera}?A:T;
类型Store={[P in keyof T]:ObjectInfer};
//递归处理options对象,并将模块定义上移一级
常量存储=(createStore(选项)为未知)为存储;
控制台日志(存储);
//输出:
/* 
{
国家:{},
建筑物:{
国家:{},
学校:{
国家:{}
},
咖啡厅:{
国家:{}
}
}
}
*/

我希望存储的类型如上所示是正确的,但是类型转换没有按预期工作,并且仍然具有与选项对象相同的结构。

好的,原始
存储的一个问题是像
{[K in keyof T]:XXX}
这样的映射类型将具有与
T
相同的键。因此,如果
T
有一个
modules
属性,那么
存储也有一个属性。另一个问题是它不是递归的
ObjectInfer
提取
T
modules
属性(如果有),但它不会深入到这些属性中执行相同的操作

实际实现必须是递归的,并且实际上从输出中省略
模块
键。以下是一种可能的方法:

type Store<T> = T extends { modules: infer A }
  ? (StoreMap<Omit<T, "modules"> & A> extends infer S
      ? { [K in keyof S]: S[K] }
      : never)
  : T;
type StoreMap<T> = { [K in keyof T]: Store<T[K]> };
看起来不错!希望有帮助。祝你好运


我正要说,您没有向我们展示实际移动属性的代码,但我有一个可怕的想法:也许您认为
as Store
以某种方式为您做到了这一点?但是
作为
是一个纯粹的编译时,而不是任何类型的编译。类型系统,包括任何类型断言,都是由运行时完成的。createStore函数实际上做了很多工作,因此为了简单起见,我将其排除在外。我在获取预期输出时没有遇到问题,但在让typescript识别对象已更改时遇到问题。我将更新函数,以提供更多关于为什么会发生这种情况的上下文。哦,好吧。。。因此,
console.log()
显示了正确的输出,但是您对函数中的类型不满意;我误解了这个问题。谢谢你,这正是我想要的。+1的简明解释。我已经将类型转换移到了createStore方法中,因为我不希望用户每次都写强制转换。是的,
createStore
的签名应该类似于
createStore(选项:t):Store
,尽管您可能需要在实现中执行一些类型断言尼斯提示是的,您可以将
Prettify
分解为自己的类型别名,但可能需要注意的是,有时编译器在检查类型时可能会显示名称
Prettify
type StoreUgly<T> = T extends { modules: infer A }
  ? StoreUglyMap<Omit<T, "modules"> & A>
  : T;
type StoreUglyMap<T> = { [K in keyof T]: StoreUgly<T[K]> };
type OutputType = Store<typeof options>;
/* 
type OutputType = {
    state: {};
    buildings: {
        state: {};
        school: {
            state: {};
        };
        cafe: {
            state: {};
        };
    };
} 
*/