Home > Back-end >  Switch with specific type in TypeScript not working
Switch with specific type in TypeScript not working

Time:12-14

I am trying to implement constants in interface, but dont know why it gives error while acessing data in switch case.

If I use just string in interface instead of constants APP_STATUS then it works fine.

Example:

//Gives error
interface InconsistenciesData {
  type: typeof APP_STATUS.INCONSISTENCIES;
  data: Inconsistency[];
}

//Works fine
interface InconsistenciesData {
  type: 'INCONSISTENCIES';
  data: Inconsistency[];
}

Below are my code snippets.

types.ts

export const APP_STATUS = {
  CONFIRMED: 'CONFIRMED',
  INCONSISTENCIES: 'INCONSISTENCIES',
  SUCCESS: 'SUCCESS',
  ERROR: 'ERROR',
  LOADING: 'LOADING',
  OK: 'OK'
}

interface InconsistenciesLoading {
  type: typeof APP_STATUS.LOADING;
}

interface InconsistenciesError {
  type: typeof APP_STATUS.ERROR;
}

interface InconsistenciesSuccess {
  type: typeof APP_STATUS.SUCCESS;
}

interface InconsistenciesData {
  type: typeof APP_STATUS.INCONSISTENCIES;
  data: Inconsistency[];
}

export type ViewState = InconsistenciesData | InconsistenciesSuccess | InconsistenciesLoading | InconsistenciesError;

My react component

const [viewState, setViewState] = useState<ViewState>({type: APP_STATUS.LOADING})
const renderPageContent = () => {
  switch (viewState.type) {
    case APP_STATUS.INCONSISTENCIES:
      return <InconsistenciesTable inconsistencies={viewState.data} />  //Error: Property 'data' does not exist on type 'ViewState'. Property 'data' does not exist on type 'InconsistenciesSuccess'.
    case APP_STATUS.ERROR:
      return <Forbidden />
    case APP_STATUS.SUCCESS:
      return <ThankYouContent />
    case APP_STATUS.LOADING:
      return <Loading />
  }
}

CodePudding user response:

Just replace your object with an enum, that's what they're for:

export enum APP_STATUS {
  CONFIRMED,
  INCONSISTENCIES,
  SUCCESS,
  ERROR,
  LOADING,
  OK,
}

export interface Inconsistency {};

export interface InconsistenciesLoading {
  type: APP_STATUS.LOADING;
}

export interface InconsistenciesError {
  type: APP_STATUS.ERROR;
}

export interface InconsistenciesSuccess {
  type: APP_STATUS.SUCCESS;
}

export interface InconsistenciesData {
  type: APP_STATUS.INCONSISTENCIES;
  data: Inconsistency[];
}

type ViewState = InconsistenciesData | InconsistenciesSuccess | InconsistenciesLoading | InconsistenciesError;

export const component = ({ state }: { state: ViewState }) => {
    switch (state.type) {
        case APP_STATUS.INCONSISTENCIES:
            console.log(state.data); // Look ma, no error!
    }
};

Playground

Your version fails because unlike an enum your APP_STATE constant is actually just a regular mutable object: there's no guarantee that your compile-time type will still hold when the switch statement actually takes effect at runtime.

CodePudding user response:

export enum APP_STATUS {
  CONFIRMED = 'CONFIRMED',
  INCONSISTENCIES = 'INCONSISTENCIES',
  SUCCESS = 'SUCCESS',
  ERROR = 'ERROR',
  LOADING = 'LOADING',
  OK = 'OK'
}

export interface Inconsistency {};

export interface InconsistenciesLoading {
  type: APP_STATUS.LOADING;
}

export interface InconsistenciesError {
  type: APP_STATUS.ERROR;
}

export interface InconsistenciesSuccess {
  type: APP_STATUS.SUCCESS;
}

export interface InconsistenciesData {
  type: APP_STATUS.INCONSISTENCIES;
  data: Inconsistency[];
}

type ViewState = InconsistenciesData | InconsistenciesSuccess | InconsistenciesLoading | InconsistenciesError;

I have added String enums, becuase I was using these status in other files also, like:

if(response.status === APP_STATUS.SUCCESS) {
  //code
}
  • Related