Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

127
Vistas
Casting types in a switch

I am trying to modularize my type casting. This is my code:

export enum detailsDataTypes {
  MACHINE = 'MACHINE',
  USER = 'USER',
  ABSTRACT = 'ABSTRACT',
}

export type sharedTypes = {
  name?: string;
  OEECategory?: string;
  OAECategory?: string;
  color?: string;
  type?: detailsDataTypes;
};

export type AbstractData = sharedTypes & {
  layer: string;
};

export type UserData = sharedTypes & {
  timeout: number;
  stateAfterTimeout: string;
  accessCanChoose: string;
  accessCanOverride: string;
};

export type MachineData = sharedTypes & {
  stateCategory: string;
  timeout: number;
  stateAfterTimeout: string;
  accessCanChoose: string;
  accessCanOverride: string;
  canOverrideOnlyByStates: boolean;
};

type DetailsData = AbstractData | UserData | MachineData;

export const detailsDataCaster = (data: DetailsData): DetailsData | null => {
  switch (data.type) {
    case detailsDataTypes.ABSTRACT:
      return <AbstractData>data;
    case detailsDataTypes.MACHINE:
      return <MachineData>data;
    case detailsDataTypes.USER:
      return <UserData>data;
    default:
      console.log('Wrong data type. Go yell at backend team or check your mocks');
      return null;
  }
};

What I'm trying to achieve, is tell TS that I'm returning AbstractData OR UserData OR MachineData OR null. But now, it doesn't like me doing this:

export const Details: FC<IDetails> = ({ data: $data = mockUserData }): ReactElement => {
  const data = detailsDataCaster($data);
  switch (data.type) {
    case detailsDataTypes.ABSTRACT:
      return <>Abstract</>;
    case detailsDataTypes.MACHINE:
      return <>Machine</>;
    case detailsDataTypes.USER:
      return <UserDisplay data={data} />; // error is here
    default:
      return <div />;
  }
};

Error

Type 'DetailsData' is not assignable to type 'UserData'.
  Type 'AbstractData' is not assignable to type 'UserData'.
    Type 'AbstractData' is missing the following properties from type '{ timeout: number; stateAfterTimeout: string; accessCanChoose: string; accessCanOverride: string; }': timeout, stateAfterTimeout, accessCanChoose, accessCanOverride

As I understand | does not mean OR in TS. I know there is the AND &, but this would make no sense. I thought that if I cast, it would be clear as to what I'm returning, but I see it's not so simple. What am I missing?

about 4 years ago · Juan Pablo Isaza
2 Respuestas
Responde la pregunta

0

If every type extending the sahredTypes would specify its own type the switch will magically work:

export enum detailsDataTypes {
  MACHINE = 'MACHINE',
  USER = 'USER',
  ABSTRACT = 'ABSTRACT',
}

export interface sharedTypes {
  name?: string;
  OEECategory?: string;
  OAECategory?: string;
  color?: string;
  type?: detailsDataTypes;
};

export interface AbstractData extends sharedTypes {
  type: detailsDataTypes.ABSTRACT;

  layer: string;
};

export interface UserData extends sharedTypes {
  type: detailsDataTypes.USER;

  timeout: number;
  stateAfterTimeout: string;
  accessCanChoose: string;
  accessCanOverride: string;
};

export interface MachineData extends sharedTypes {
  type: detailsDataTypes.MACHINE;

  stateCategory: string;
  timeout: number;
  stateAfterTimeout: string;
  accessCanChoose: string;
  accessCanOverride: string;
  canOverrideOnlyByStates: boolean;
};

type DetailsData = AbstractData | UserData | MachineData;

Playgound link that shows the type is correctly inferred from the switch.

about 4 years ago · Juan Pablo Isaza Denunciar

0

You might want to add a discriminant value to each type like this...

export type AbstractData = sharedTypes & {
  layer: string;
  type: detailsDataTypes.ABSTRACT; // add this field, it can only be of this literal value
};

export type UserData = sharedTypes & {
  timeout: number;
  stateAfterTimeout: string;
  accessCanChoose: string;
  accessCanOverride: string;
  type: detailsDataTypes.USER; // add this field
};

export type MachineData = sharedTypes & {
  stateCategory: string;
  timeout: number;
  stateAfterTimeout: string;
  accessCanChoose: string;
  accessCanOverride: string;
  canOverrideOnlyByStates: boolean;
  type: detailsDataTypes.MACHINE; // add this field
};

type DetailsData = AbstractData | UserData | MachineData;
function Details(data: DetailsData) {
    switch (data.type) {
        case detailsDataTypes.ABSTRACT:
            data; // data is AbstractData
            break;
            
        case detailsDataTypes.MACHINE:
            data; // data is MachineData
            break;

        case detailsDataTypes.USER:
            data; // data is UserData
            break;

        default:
            data; // data is never (no more possibilities left!)
            break;
    }
}

This technique is called discriminated unions.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda