在 TypeScript 中将 JSON 对象转换为接口时忽略大小写
当 JSON 中的一些成员仅在大小写上与接口的成员不同时,有没有办法将 jsonObj "转换" 为某个接口?
interface Desire {
propTest1: string,
propTest2: string
}
let jsonFromApi = {
PropTest1: "aa",
PropTest2: "bb"
}
let result = smartCast<Desire>(jsonFromApi);
console.log(results)
// I expect {
propTest1: "aa",
propTest2: "bb"
}
这是我到目前为止尝试过的:
function smartCast<T>(from: object): T{
type LOWERCASE = { [p in keyof T & string as Lowercase<`${p}`>]: T[p] }
type LOWERCASE_MAP = { [p in keyof T & string as Lowercase<`${p}`>]: p }
const lowerCase = Object.entries(from).reduce((a: any, [key, val]) => {
a[key.toLowerCase()] = val;
return a;
}, {}) as LOWERCASE;
console.log("lowercase ", lowerCase)
const lowerCaseMap = Object.entries(lowerCase).reduce((a: any, [key, val]) => {
a[key] = key;// how to get something like LOWERCASE_MAP[key] ?? typescript === runtime without types :(((
return a;
}, {});
return Object.entries(lowerCase).reduce((a: any, [key, val]) => {
a[lowerCaseMap[key]] = val
}, {}) as T;
}
答案#1
你想在运行时更改从 API 获取的 JSON 对象的属性大小写。但这些对象最初的 TypeScript 定义在哪里?解析 JSON 通常会在设计时给你 any 类型,除非你使用的 API 库已经返回了类型化的对象。
如果你没有类型定义,或者你无论如何都要手动重新创建它们,只需将你的 case 修改函数的返回类型设置为此类型。你不需要为此使用 TypeScript 的泛型:
type AnyObject = {[index: string]: unknown};
interface DesiredResultObject {
prop1: string;
prop2: number;
}
const jsonObject = {
Prop1: "answer",
Prop2: 42,
}
function toLowerCaseProps(obj: AnyObject): DesiredResultObject {
return Object.entries(obj).reduce((a, [key, val]) => {
a[key.toLowerCase()] = val;
return a;
}, {} as AnyObject) as unknown as DesiredResultObject;
}
const result = toLowerCaseProps(jsonObject);
如果你已经拥有 API 对象的类型定义,并且想要转换它们的键,但又不想手动创建新的类型定义,你可以这样做:
type AnyObject = {[index: string]: unknown};
type LowerCaseProps<T extends AnyObject> = {
[K in keyof T as Lowercase<string & K>]: T[K]
};
const jsonObject = {
Prop1: "answer",
Prop2: 42
}
function toLowerCaseProps<T extends AnyObject>(obj: T): LowerCaseProps<T> {
return Object.entries(obj).reduce((a, [key, val]) => {
a[key.toLowerCase()] = val;
return a;
}, {} as AnyObject) as LowerCaseProps<T>;
}
const result = toLowerCaseProps(jsonObject);
console.log(result.prop1); // outputs "answer"
// console.log(result.Prop1); // this won't compile
console.log(result.prop2); // outputs 42
// console.log(result.Prop2); // this won't compile
