首页 > 解决方案 > 将 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;    
}

标签: typescript

解决方案


您想要更改在运行时从 API 获得的 JSON 对象的属性的大小写。但是对象的打字稿定义最初来自哪里?解析 JSON 通常会让您any在设计时输入类型,除非您使用已经返回类型化对象的 API 库。

如果您没有类型定义,或者无论如何您要手动重新创建它们,只需将您的案例修改函数的返回类型设置为这种类型。您不需要为此使用打字稿的泛型:

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

推荐阅读