avkonst/hookstate

Typescript error when defining a state with OR operator

emroot opened this issue · 5 comments

Hey there,

I'm have this code:

import { hookstate, useHookstate } from '@hookstate/core';

interface DraggableStoreNotDraggingState {
  dragging: false;
  waiting: false;
}

interface DraggableStoreWaitingState {
  dragging: false;
  waiting: true;
  waitingPoint: { x: number; y: number };
}

export interface DraggableStoreDraggingState {
  dragging: true;
  waiting: false;
  startingPoint: { x: number; y: number };
  currentPoint: { x: number; y: number };
}

type DraggableStoreState =
  | DraggableStoreDraggingState
  | DraggableStoreNotDraggingState
  | DraggableStoreWaitingState;

export const InitalState = Object.freeze({
  dragging: false as false,
  waiting: false as false,
});

const DraggableStore = hookstate<DraggableStoreState>({ ...InitalState });

if (DraggableStore.waiting.get()) {
  // typescript error
  DraggableStore.waitingPoint.get();
}

Basically typescript says that waitingPoint is undefined though waiting is true.

How should this be done?

Thanks

The error is caused by the fact that the DraggableStore state object is not guaranteed to have a waitingPoint property when the waiting property is true. To fix this, you can add a type guard to check if the state object has a waitingPoint property before trying to access it.

if (DraggableStore.waiting.get() && 'waitingPoint' in DraggableStore.get()) {
  DraggableStore.waitingPoint.get();
}

Hope the advise above helped. If not please reopen.

I am having the same issue as above and the proposed solution is not working for me.

I have the following type

interface BaseHole {
  surface: number,
  x: number,
  y: number,
}

interface CircleHole extends BaseHole {
  shape: 'circle',
  diameter: number,
}

interface SquareHole extends BaseHole {
  shape: 'square',
  width: number,
}
interface RectangleHole extends BaseHole {
  shape: 'rectangle',
  length: number,
  width: number,
}

type Hole = CircleHole | SquareHole | RectangleHole

And the following React conditional

{
  (hole.shape.value === 'square' && 'width' in hole.keys) &&
  <NumberInput label="Width" value={hole.width.value} onChange={(e) => hole.width.set(e.target.value)} />
}

And I get the error

Property 'width' does not exist on type '__State<Hole, {}> & StateMethods<Hole, {}> & Omit<{ readonly shape: State<"circle", {}>; readonly diameter: State<number, {}>; readonly surface: State<...>; readonly x: State<...>; readonly y: State<...>; }, keyof StateMethods<...>>'.

I tried hole.keys and hole.get().

And on a related note I have the following select field

<select value={hole.shape.value} onChange={(e) => hole.shape.set(e.target.value as 'circle' | 'square' | 'rectangle')}>
  <option value="circle">Circle</option>
  <option value="square">Square</option>
  <option value="rectangle">Rectangle</option>
</select>

And I get the following error

Argument of type '"circle" | "square" | "rectangle"' is not assignable to parameter of type '(SetStateAction<"circle"> & SetStateAction<"square">) & SetStateAction<"rectangle">'.
  Type '"circle"' is not assignable to type '(SetStateAction<"circle"> & SetStateAction<"square">) & SetStateAction<"rectangle">'