TypeScript递归地将对象键从PascalCase转换为CamelCase格式

m1m5dgzv  于 2022-11-26  发布在  TypeScript
关注(0)|答案(3)|浏览(164)

我需要创建一个函数来修改对象的键从PascalCase到CamelCase格式。即

const input = {
    FirstName: 'John',
    LastName: 'Smith'
};

const expectedOutput = {
    firstName: 'John',
    lastName: 'Smith'
};

// function looks as follows
function pascalToCamelCase<T>(input: T): CamelCaseKeys<T> {
    if (typeof input !== 'object' || input === null) {
        return input;
    }

    // do conversion....
    return output;
}

但我不知道如何通过CamelCaseKeys相应地修改密钥

jdg4fx2g

jdg4fx2g1#

好吧,我今天学到了一些东西!我们可以使用新的typescript 4.1模板字符串文字特性和实用程序方法以类型安全的方式实现这一点。
Capitalize<T>将大写字符串。
Uncapitalize<T>将一个字符串(您要查找的字符串)变为非大写。
关于这些的更多信息here
从这两个我们可以建立一个辅助类型UncapitalizeObjectKeys<T>

type UncapitalizeKeys<T extends object> = Uncapitalize<keyof T & string>;

type UncapitalizeObjectKeys<T extends object> = {
  [key in UncapitalizeKeys<T>]: Capitalize<key> extends keyof T ? T[Capitalize<key>] : never;
}

备注:

  • Uncapitalize<keyof T & string>-我们与string相交,只得到T的键,它们是字符串,因为我们不能大写数字或符号
  • 我们必须先将[key in UncapitalizeKeys<T>]中的键取为非大写,然后再将它们重新大写,这样就可以用T[Capitalize<key>]从T中提取出正确的值。条件部分Capitalize<key> extends keyof T只是检查大写的、非大写的键是否仍然可以分配给keyof T,因为TS不能保持这种关系(......还没有?)。

然后,我们可以从@spender的答案中提取几个部分--替换运行时类型检查,因为TS应该能够Assert这些(假设这些对象不是来自IO:

type UncapitalizeObjectKeys<T extends object> = {
  [key in UncapitalizeKeys<T>]: Capitalize<key> extends keyof T ? T[Capitalize<key>] : never;
}

type UncapitalizeKeys<T extends object> = Uncapitalize<keyof T & string>;

export const lowerCaseKeys = <T extends object>(obj: T): UncapitalizeObjectKeys<T> => {
    const entries = Object.entries(obj);
    const mappedEntries = entries.map(
        ([k, v]) => [
            `${k.substr(0, 1).toLowerCase()}${k.substr(1)}`,
            lowerCaseKeys(v)]
    );

    return Object.fromEntries(mappedEntries) as UncapitalizeObjectKeys<T>;
};

现在我们得到了所需的输出:

Playground链接

wb1gzix0

wb1gzix02#

下面是一个递归的解决方案,我已经使用了很好的效果:

export const lowerCaseKeys = (obj: any): any => {
    if (typeof obj !== 'object') {
        return obj;
    }
    if (Array.isArray(obj)) {
        return obj.map(lowerCaseKeys);
    }
    if (obj === null) {
        return null;
    }
    const entries = Object.entries(obj);
    const mappedEntries = entries.map(
        ([k, v]) => [
            `${k.substr(0, 1).toLowerCase()}${k.substr(1)}`,
            lowerCaseKeys(v)] as const
    );
    return Object.fromEntries(mappedEntries);
};

Playground链接

r7xajy2e

r7xajy2e3#

我将在这里放置更现代的答案只是为了可见性。虽然其他答案中的实现是正确的,但我认为这种类型更优雅。

type UncapitalizeObjectKeys<T> = {
  [key in keyof T as Uncapitalize<key & string>]: T[key]
}

4.1以后的作品

相关问题