在新对象中展开多个对象时防止属性重叠

问题描述 投票:0回答:4

假设我们有

x = {a:65, b:634, c:74};
y = {o:453, e:5342, g:543}
z = {o:453, e:5342, b:543}


// Doing this should be okay
const both = {...x, ...y}

// However, when doing this:
const both = {...x, ...z}

我需要它显示一些错误,例如“属性 b 无法重新分配”或其他什么,只是不要让它编译。有什么建议吗?

编辑: 我知道我可以轻松编写一个函数来组合对象并有条件地引发异常,但重点是我需要在运行时之前进行此类检查。如果可以使用 typescript、eslint 或任何可以在运行前检查此类条件的技巧来完成,那将非常有帮助......

typescript eslint
4个回答
3
投票

最简单的方法是制作一个简单的实用函数..

您可以获取每个键的键,并使用 include 来确保该键不存在于其他键中。

例如。

const x = {a:65, b:634, c:74};
const y = {o:453, e:5342, g:543};
const z = {o:453, e:5342, b:543};

function join(a,b) {
  const ak = Object.keys(a);
  const bk = Object.keys(b);
  for (const k of bk)
    if (ak.includes(k)) 
      throw new Error(`key ${k} cannot be re-assigned`);
  return {...a, ...b};
}

console.log(join(x, y));
console.log(join(x, z));

如果您希望使用 Typescript 在设计时进行一些检查,一个想法是获取两个对象的交集类型,如果交集从不存在,那么我们可以创建一个假类型,该类型返回 true,如果重叠则返回 false。 如果您随后尝试将 true 分配给该类型并且存在重叠,您将收到错误。 好的捆绑器上的假分配也应该删除这个假声明。

例如。

const x = {a:65, b:634, c:74};
const y = {o:453, e:5342, g:543};
const z = {o:453, e:5342, b:543};

type NoOverlap<A extends object, B extends object> = 
  keyof A & keyof B extends never ? true : false;

const _dummy1:NoOverlap<typeof x, typeof y> = true;
const _dummy2:NoOverlap<typeof x, typeof z> = true; //this will error.

TS游乐场


2
投票

这是一个有 n 个参数的解决方案:

function combineNoOverwrite(...args) {
  return args.reduce((acc, cur) => {
    for (var key in cur) {
      if (cur.hasOwnProperty(key) && !acc.hasOwnProperty(key)) {
        acc[key] = cur[key];
      } else {
        throw new Error(`key ${key} cannot be re-assigned`);
      }
    }
    return acc;
  });
}

0
投票

您可以使用以下内容。

function combine(x, y) {
    const array = Object.keys(x).concat(Object.keys(y))
    if (array.length != [...new Set(array)].length) {
        console.error("Error: Duplicate Key")
        return
    } 
    return {...x, ...y}
}

0
投票

这可以仅使用 Typescript 来完成,并且可以扩展到任意数量的跨度。

/**
 * Given a tuple of interfaces, this resolves immediately to the duplicate keys
 * of the first offending item in the tuple. If there are no offending members
 * in the tuple, this resolves to 'never'.
 */
type SomeDuplicateKeys<T extends Object[]> = T extends [
  infer H1 extends Object,
  infer H2 extends Object,
  ...infer R extends Object[],
]
  ? keyof H1 & keyof H2 extends never
    ? SomeDuplicateKeys<[H1 & H2, ...R]>
    : keyof H1 & keyof H2
  : never;

type UnionNoDuplicateKeysAllowed<T extends Object[]> =
  SomeDuplicateKeys<T> extends never ? T[number] : never;

const x = { a: 65, b: 634, c: 74 };
const y = { o: 453, e: 5342, g: 543 };
const z = { o: 453, e: 5342, b: 543 };

// Okay.
const foo: UnionNoDuplicateKeysAllowed<[typeof x, typeof y]> = { ...x, ...y };

// Error: Type '{ o: number; e: number; b: number; a: number; c: number; }' is not assignable to type 'never'. (2322)
const bar: UnionNoDuplicateKeysAllowed<[typeof x, typeof z]> = { ...x, ...z };
© www.soinside.com 2019 - 2024. All rights reserved.