重命名对象的多个键

问题描述 投票:1回答:1

我正在尝试基于哈希重命名对象中的键,即:

interface Foo {
  a: number;
  b: number;
  c: number;
}

const f: Foo = null!;
// Change the Foo.b prop to Foo.d and keep the same type
const g = rename(f, { b: "d" } as const);
g.a = 1;
// @ts-expect-error b went away
g.b = 2;
// This works but only b/c I hard-coded `number` in `TValue`
g.d = 2;

我认为我很亲密:

// TODO Don't hardcode `number` here, instead get the T[K] type for the "right K" for P
type TValue<T, M extends { [P in keyof T]?: string }, P extends M[keyof M]> = number;

type Replace<T, M extends { [P in keyof T]?: string }> = Omit<T, keyof M> &
  {
    // K in keyof M where M[K] == P --> use T[K];
    [P in Exclude<M[keyof M], undefined>]: TValue<T, M, P>;
  };

function rename<T, M extends { [P in keyof T]?: string }>(t: T, mapped: M): Replace<T, M> {
  return t as any;
}

但是“我有这个值,即来自M的值” d”的部分,是什么)a)T是什么?[k]“ b”是那个“ d”,b)T是什么[K]类型”使我难以理解。

我发现了其他一些SO问题/答案,例如Rename keys of an object/interface typesafe,但它们在映射中具有诸如string的硬编码类型,而不是使用T[K]的原始类型。

typescript
1个回答
0
投票

创建一个将原始键映射到重命名键和新类型的帮助程序类型,然后提取给定重命名键的类型:

type RenameMap<T> = Partial<Record<keyof T, PropertyKey>>;

type RenamedKeys<T, M extends RenameMap<T>> = {
    [K in keyof T]: { name: M[K], t: T[K] }
}[keyof T];

type Replace<T, M extends Partial<Record<keyof T, PropertyKey>>> = Omit<T, keyof M> & {
    [K in Exclude<M[keyof M], undefined>]: Extract<RenamedKeys<T, M>, { name: K }>['t']
};

function rename<T, M extends RenameMap<T>>(
    t: T, mapped: M
): Replace<T, M> {
    return t as any;
}
© www.soinside.com 2019 - 2024. All rights reserved.