javascript - 递归重新映射对象中的键时键入返回值
问题描述
我有一个接收任何对象的映射器,如果其中有一个名为“字段”的键,它会被它的内容替换。例如,
const obj = { x: 'hey', fields: { y: 'you' } }
const mapped = contentfulMapper(obj);
// mapped = { x: 'hey', y: 'you' }
或者
const givenObj = {
a: "sdf",
w: {
a2: 343,
a3: true,
fields: {
a4: "ll",
q: {
fields: {
a5: [2, 4, "lk"]
},
},
},
},
};
const mapped = contentfulMapper(givenObj);
/* mapped = {
a: "sdf",
w: {
a2: 343,
a3: true,
a4: "ll",
q: {
a5: [2, 4, "lk"]
},
},
}; */
虽然返回 aRecord<string, unknown>
不是很好,所以我的问题是如何正确输入?
type TContentfulModel = {
fields?: undefined | Record<string, TContentfulModel>;
};
const contentfulMapper = (
obj: Record<string, TContentfulModel | unknown>
) => {
let out: Record<string, unknown> = {};
Object.keys(obj).forEach((key) => {
const field = obj[key] as TContentfulModel;
if (key === 'fields') {
const mappedField = contentfulMapper(field);
out = { ...out, ...mappedField };
} else {
out[key] =
typeof obj[key] === 'object' && !Array.isArray(obj[key])
? contentfulMapper(field)
: obj[key];
}
});
return out;
};
解决方案
这是一个有效的解决方案。请通过它,如果没有得到任何东西,请告诉我。那么,我将添加任何需要的解释。
type TContentfulModelExtended = {
fields: TContentfulModelExtended | TContentfulModel
[key: string]: any
}
type TContentfulModel = {
[key: string]: any
}
// if `T` has `fields`, we omit that key, keep rest,
// and take it's intersection with the flatten nested fields
type Flat<T extends TContentfulModelExtended | TContentfulModel> = T extends TContentfulModelExtended
? Omit<T, 'fields'> & Flat<T['fields']>
: T
type MyObjType = {
a: string
fields: {
b: number
c: boolean
fields: {
d: number[],
fields: {
e: Promise<number>
}
}
}
}
type Flattened = Flat<MyObjType>
const obj: Flattened = {
a: 'abc',
b: 3,
c: false,
d: [3],
e: Promise.resolve(3)
}
const contentfulMapper = <O extends TContentfulModelExtended | TContentfulModel>(obj: O) => {
let out: Flat<O> = {} as any;
Object.keys(obj).forEach((key) => {
const field = obj[key];
if (key === 'fields') {
// @ts-ignore
const mappedField = contentfulMapper(field);
out = { ...out, ...mappedField };
} else {
out[key] =
typeof obj[key] === 'object' && !Array.isArray(obj[key])
? contentfulMapper(field)
: obj[key];
}
});
// @ts-ignore
return out;
};
const givenObj = {
a: 'sdf',
fields: {
a2: 343,
a3: true,
fields: {
a4: 'll',
fields: {
a5: [2, 4, 'lk']
}
}
}
}
const objSpreaded = contentfulMapper(givenObj)
objSpreaded.a // all props from `a` to `e` works properly
objSpreaded.a2
objSpreaded.a3
objSpreaded.a4
objSpreaded.a5
objSpreaded.f // expected error
请注意,我添加了编译器指令注释// @ts-ignore
以消除无限深度错误。
推荐阅读
- c# - 我可以在 Visual Studio 监视窗口中仅显示 ac# 集合的子集吗?
- powershell - Powershell脚本不输出第二个Where-Object
- javascript - 添加关键帧时,Transform Rotate 在我的 CSS 上不起作用
- loops - Instagram 抓取公共个人资料的随机列表
- python - 如何保护 dockerized python 容器
- javascript - 反应本机导航器
- python - Python Numpy - 切片分配未正确分配
- sqlite - 空表上选择输出中的 SQLite 虚拟值
- ios - 在 Swift 中处理 Web 查询后延迟 endRefreshing 2 秒
- docker-compose - 由于动态 IP,Docker compose 无法从另一个服务访问一个服务