Looking at the following code:
enum ActionName {
BUMP = "BUMP",
CLAP = "CLAP",
INSPECT = "INSPECT",
RUN = "RUN",
TALK = "TALK",
WALK = "WALK",
WAVE = "WAVE",
}
export enum ActionState {
INACTIVE,
MAP_ACTIVE,
UI_ACTIVE,
ENDED,
}
type TactionContext = "action" | "communication" | "reaction";
type Taction = {
action: ActionName.BUMP;
communication: ActionName.INSPECT | ActionName.TALK;
reaction: ActionName.CLAP | ActionName.WAVE;
};
export type Tanimate<T> = (args: {
name: T;
onEnd?: () => void;
}) => void;
interface IactionContextVar<K extends TactionContext> {
name: Taction[K];
animate?: Tanimate<Taction[K]>;
state: ActionState;
}
export interface IplayerActionVar {
action: IactionContextVar<"action"> | null;
communication: IactionContextVar<"communication"> | null;
reaction: IactionContextVar<"reaction">;
}
export type Tregistered = {
[C in TactionContext]: Map<string, IactionContextVar<C>>;
};
const registered: Tregistered = {
action: new Map(),
communication: new Map(),
reaction: new Map(),
};
type Tregister = <T extends TactionContext>(args: {
context: T;
id: string;
data: Omit<IactionContextVar<T>, "state">;
}) => void;
export const register: Tregister = ({ context, id, data }) => {
registered[context].set(id, {
...data,
state: ActionState.INACTIVE, <== TS-ERROR !
});
};
When attempting to register a new action in my registered object, I encounter an error
type ActionState is not assignable to type 'never'
.
The TypeScript error message is as follows:
[tsserver 2345] [E] Argument of type 'IactionContextVar' is not assignable to parameter of type 'never'. The intersection 'IactionContextVar<"action"> & IactionContextVar<"communication"> & IactionContextVar<"reaction">' was reduced to 'never' because property 'name' has conflicting types in some constituents.
I'm trying to properly type the calls to register based on the specific context (e.g., for a "TALK" action, it should be under the "communication" context).
The current workaround involves duplicating the function code three times:
type Tregister <T extends TactionContext>= (args: {
context: T;
id: string;
data: Omit<IactionContextVar<T>, "state">;
}) => void;
export const registerAction: Tregister<"action"> = ({ context, id, data }) => {
registered[context].set(id, {
...data,
state: ActionState.INACTIVE,
});
};
export const registerCommunication: Tregister<"communication"> = ({ context, id, data }) => {
registered[context].set(id, {
...data,
state: ActionState.INACTIVE,
});
}
export const registerReaction: Tregister<"reaction"> = ({context, id, data}) => {
registered[context].set(id, {
...data,
state: ActionState.INACTIVE,
});
};
I would like TypeScript to recognize the three distinct scenarios here and avoid amalgamating different types into an intersection. Is there a way to achieve this?