Estoy tratando de modularizar mi tipo de fundición. Este es mi código:
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; } }; Lo que estoy tratando de lograr es decirle a TS que estoy devolviendo AbstractData OR UserData OR MachineData OR null . Pero ahora, no le gusta que haga esto:
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 Según tengo entendido | no significa OR en TS. Sé que existe el AND & , pero esto no tendría sentido. Pensé que si lanzo, sería claro en cuanto a lo que estoy devolviendo, pero veo que no es tan simple. ¿Qué me estoy perdiendo?
Si cada tipo que extiende los sahredTypes especificara su propio type , el cambio funcionará mágicamente:
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;Enlace de Playgound que muestra que el tipo se infiere correctamente del interruptor.
Es posible que desee agregar un valor discriminante a cada tipo como este ...
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; } }Esta técnica se llama uniones discriminadas .