1

Problem

In the code below, I want to make the property 'size' and 'fixSize' only one can be set.

interface Size {
  size: number;
}

interface FixSize {
  fixSize: number;
}

type Demo = Size | FixSize;

let a: Demo = {
  size: 1,
  fixSize: 1
}

Not so perfect solution

I use never to improve it。 Now, people who pass a value to Size cannot set 'size' and 'fixSize'. However, people who read value from Size will also can see fixSize and Size.

interface Size {
  size: number;
  fixSize?: never;
}

interface FixSize {
  fixSize: number;
  size?: never;
}

type Demo = Size | FixSize;

let a: Demo = { // ok, it errors
  size: 1,
  fixSize: 1
}

// however...
function sizeFn(a: Demo) {
  if (isSize(a)) {
    a.fixSize; // I don't want property 'fixSize' can be get.
    a.size;
  } else {

  }
}

function isSize(a: Demo): a is Size {
  return 'size' in a;
}

playground is here.

zongchen
  • 11
  • 2

1 Answers1

0

While I understand your concern, you shouldn't declare a variable "Demo", but one if it's constituent types. sizeFn will receive the union type as argument, like you wrote, but TS will force you to check it's type before accessing any of it's (distinct) attributes.

Your first example actually works, minus that a variable that you shouldn't declare.

interface Size {
  size: number;
}

interface FixSize {
  fixSize: number;
}

type Demo = Size | FixSize;

function sizeFn(a: Demo) {
  if ('size' in a) {
    console.log(a.size);
    console.log(a.fixSize); // this will error
  } else {
    console.log(a.fixSize);
    console.log(a.size); // this will error
  }
}
  • In first example, read value from Demo is ok, but when you call the sizeFn, you can set both size and fixSize. If my 'sizeFn' is exported to others to use, it will be confuse. ```sizeFn({size: 1, fixSize: 1}); // this won't error``` – zongchen Jun 30 '22 at 09:12