0

I have a simple object type like this:

  type Props = { foo: boolean } | { bar: boolean };
  const props: Props = { foo: true }: 

So props.foo or props.bar can be defined at any time.

I know props.foo and props.bar can be not present, meaning it will be undefined, but I need to detect changes in a "dependency array" like this:

useEffect(() => {}, [props.foo, props.bar]);

Typescript complains that foo may not exist exist and same with bar. But I know this, I don't want typescript to complain. I just need to know if they have change. Anyway to tell Typescript, that "hey I know it may not be there, so it's going to be undefined, and that's an ok value"?

I can to mark prop keys as optional ? because then people think its optional when using this type but its not. And I use typegaruds based on existence.

Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • But @brc-dd I use the existance as typegaurds, so I cant do that :( – Noitidart Jun 25 '22 at 13:39
  • 3
    Does this answer your question? [Excess properties not inferred correctly in unions : any workarounds?](https://stackoverflow.com/questions/70820885/excess-properties-not-inferred-correctly-in-unions-any-workarounds) – jsejcksn Jun 25 '22 at 13:42
  • Maybe do a conditional check for the existence of each key in the props before accessing it and only pass props to your dependency array. – George Makroglou Jun 25 '22 at 13:48
  • Thanks jsejcksn - that was a great topic, I appreciate @brc-dd solution below as it's very concise. That question over there is verbose and not as simply asked, even I read it before I wouldn't have recognized it haha. Thanks for sharing the topic! – Noitidart Jun 26 '22 at 20:29

1 Answers1

2

Change your type to this:

type Props =
  | { foo: boolean; bar?: never }
  | { foo?: never; bar: boolean };

Suppose you have something like this:

const FooBar: React.FC<Props> = (props) => {
  const [curr, setCurr] = useState('');

  useEffect(() => {
    if ('foo' in props) setCurr('foo');
    else setCurr('bar');
  }, [props.foo, props.bar]);

  return <div>{curr}</div>;
};

Now, your users will only be able to do this:

<FooBar foo />
<FooBar bar />

// invalid:
<FooBar />
<FooBar foo bar />

So it won't affect whatever type guards you have.

Stackblitz: https://stackblitz.com/edit/react-ts-k4yjjd?file=App.tsx

brc-dd
  • 10,788
  • 3
  • 47
  • 67