Type 'IConnectionState' is not assignable to type '{ connected: false; type: "none"; }'

372 Views Asked by At

So, I think my typescrpt linter is short circuiting because, I cant for the life of me figure out why this linting error keeps being raised.

Type 'IConnectionState' is not assignable to type '{ connected: false; type: "none"; }'

Below is my code, which you can clearly see, should have no consequence.


export interface IConnectionState {
    connected: boolean;
    type: 'none' | 'player' | 'host';
}

export const ConnectionState: RecoilState<IConnectionState> = atom({
    key: 'connectionState',
    default: {
        connected: false,
        type: 'none'
    }
});

If it helps, I'm using recoil. But looking at the recoil types, RecoilState should type takes a subtype of the default value given to its options object.

I'm so lost.

3

There are 3 best solutions below

0
On

Actually the linter is working as expected. You are setting the type of ConnectionState to be IConnectionState but you never include the property key in the interface.

Interface IConnectionState is correct but it should be nested within another Interface.

const NONE = 'none';
const PLAYER = 'player';
const HOST = 'host';
const CONNECTIONSTATE = "connectionState";

type TType = typeof NONE | typeof PLAYER | typeof HOST;

interface IConnectionStateDefault {
    connected: boolean;
    type: TType
}

interface IConnectionState {
    key: typeof CONNECTIONSTATE,
    default: IConnectionStateDefault
}


export const ConnectionState: RecoilState<IConnectionState> = atom({
    key: "connectionState",
    default: {
        connected: false,
        type: 'none'
    }
});

If IConnectionState has more key values to it then just do the same as I did with TType where you form a union over the possible types that key can exist as.

0
On

This is what I've been doing in our monorepo.
Create a global file for the ALL keys to try to keep awareness that you don't want any collisions since the there is one Recoil registry.

export enum GlobalRecoilKeyEnum {
     ATOM_SOME_BOOLEAN_KEY= "ATOM_SOME_BOOLEAN_KEY",
}

Create a regional file of atoms (Nx allows me to isolate access with linting.)

export const SomeBooleanAtom = atom({
    key: GlobalRecoilKeyEnum.ATOM_SOME_BOOLEAN_KEY,
    default: false
});

Ways I access in Functional Components.

const isSomeBoolean: boolean = useRecoilValue<boolean>(SomeBooleanAtom);
const setSomeBoolean: SetterOrUpdater<boolean> = useSetRecoilState<boolean>(SomeBooleanAtom);
const [isPractice, setSomeBoolean]: [boolean, SetterOrUpdater<boolean>] = useRecoilValue<boolean>(SomeBooleanAtom);
0
On

I see a similar problem with a simpler interface.

export const myState: RecoilState<boolean> = atom({
  key: 'myState',
  default: false,
});

// Type '<RecoilState<false>' is not assignable to type 'RecoilState<boolean>'.

I can fix it by either declaring default: false as boolean, or, probably better, by adding the generic <T> in the method call:

export const myState: RecoilState<boolean> = atom<boolean>({
  key: 'myState',
  default: false,
});

Or you can leave out the type declarations completely and TypeScript figures it out.