Steven Kalt
Steven Kalt

Reputation: 1198

Type two objects to ensure they do not share any keys

I'd like to write a function of two arguments, each of which is an object. These objects must not share keys. How do I type this constraint?

// helpers
const a=1, b=2, c=3, d=4;

// how do I type this function?
function func(x, y) {/*...*/}

func({a, b, c}, {d}) // ok; no keys are shared
func({a, b}, {b, c}) // Error; key `b` is shared.

Alternatively posed: how do I constrain a type so that it does not contain keys of another type?

const foo = {a, b};
type X = typeof foo;
type NoKeysOf<S> = {/*... */}; // <- How do I constrin this type?
const bar: NoKeysOf<X> = {d};   // ok; no keys shared
const baz: NoKeysOf<X> = {b, c} // Error; `b` is shared

Upvotes: 4

Views: 349

Answers (2)

bugs
bugs

Reputation: 15313

You can enforce this kind of constraint at compile-time with the never type.

declare function f<
  A,
  B extends { [K in keyof B]: K extends keyof A ? never : B[K] }
>(
  a: A, b: B
): any

What we are saying here is that if K, which is a key of B, extends one of the keys of A, its corresponding value in b will be of type never (hence, you could never construct it), otherwise, it'll just be B[K].

And this has exactly the desired behaviour:

const a = 1, b = 2, c = 3, d = 4;
f({ a, b, c }, { d }) // OK
f({ a, b }, { b, c }) // Error: Type 'number' is not assignable to type 'never'

Playground link

Upvotes: 3

uminder
uminder

Reputation: 26170

Personally I would write a function findSameKeys that returns all shared keys. It's up to you to also move the logic that follows into this function.

function findSameKeys(x, y) {
  const xKeys = Object.keys(x);
  return Object.keys(y).filter(k => xKeys.includes(k));
}

const o1 = { a: 1, b: 2, c: 3 };
const o2 = { x: 1, y: 2, z: 3 };
const sameKeys = findSameKeys(o1, o2);
if (sameKeys.length === 0) {
   console.log('OK: no keys are shared');
} else {
   const verb = sameKeys.length === 1 ? ' is ' : ' are ';
   console.log('Error: keys ' + sameKeys + verb + 'shared');
}

Upvotes: 0

Related Questions