键入将对象中的 属性 映射到另一个 属性 的函数

Typing a function that maps a property in an object to another property

我正在尝试键入一个将对象中的 属性 映射到另一个 属性 的函数。

例如mapProperty 函数可以用作 mapProperty('_id', 'id', { _id: "arst" } )。结果类型应该是 { id: string }.

我创建了下面输入的函数 mapProperty,但我觉得 as unknown as M 不是必需的。但是,当我不使用它时,出现以下错误:

Type 'T & { [x: string]: T[K]; }' is not assignable to type 'M'.
'M' could be instantiated with an arbitrary type which could be unrelated to 'T & { [x: string]: T[K]; }'.

也无法将 return 值键入 : { [key: L]: T[K] }

有什么解决方案?

const mapProperty = <T, K extends keyof T, M, L extends keyof M>(
  from: K,
  to: L,
  obj: T,
): M => {
  const prop = obj[from];
  delete obj[from];
  return ({ ...obj, [to]: prop } as unknown) as M;
};

编辑:(我使用了 Николай Γольцев 的答案,但稍作改动)

我添加了一个参数,它是一个映射映射值的函数 属性:

const mapProperty = <T, K extends keyof T, L extends string, M = T[K]>(
  obj: T,
  from: K,
  to: L,
  fn?: (x: T[K]) => M,
): Omit<T, K> & { [key in L]: M } => {
  const prop = fn ? fn(obj[from]) : obj[from];
  delete obj[from];
  return { ...obj, [to]: prop } as any;
};

可以这样写:

const mapProperty = <T, K extends keyof T, L extends string>(
  from: K,
  to: L,
  obj: T,
): Omit<T, K> & {
    [key in L]: T[K]
} => {
  const prop = obj[from];
  delete obj[from];
  return { ...obj, [to]: prop } as any;
};

const k = mapProperty('_id', 'id', { _id: "arst", k: true } )

return 语句中出现错误,因为 delete 运算符对变量类型不做任何操作。删除操作后仍然是T。计算 属性,据我所知,总是给出类型 { [x: string]: T }.

请看下一个解决方案:


type Data = { age: 1, name: 'string' }

// Main utility
type Replace<O, P1 extends keyof O, P2 extends string> =
    Pick<O, Exclude<keyof O, P1>>
    & { [P in P2]: O[P1] }


type Result = Replace<Data, 'name', 'surname'>

const mapProperty = <O, P1 extends keyof O, P2 extends string>(obj: O, from: P1, to: P2): Replace<O, P1, P2> => {
    const { [from]: replaced, ...rest } = obj;

    // don't know how to get rid of casting operators
    return {
        ...rest,
        [to]: replaced
    } as unknown as Replace<O, P1, P2>
}

const data: Data = { age: 1, name: 'string' }

const result = mapProperty(data, 'age', 'year')
type Res = keyof typeof result // "year" | "name"

根本不使用 delete 运算符被认为是一个好习惯,因为它很慢并且还有其他缺点。作为替代方案,您可以改用 Reflect.deleteProperty()。由于计算的性质,我不知道如何摆脱 unknown 转换 [to]。