Skip to content

Instantly share code, notes, and snippets.

@smolijar
Last active November 28, 2018 07:40
Show Gist options
  • Save smolijar/2389b02f41d04bd7ceff1d1f81c889cc to your computer and use it in GitHub Desktop.
Save smolijar/2389b02f41d04bd7ceff1d1f81c889cc to your computer and use it in GitHub Desktop.
Isa model in Typescript

ISA model in TypeScript

😿 Lousy solution

export enum ServiceType {
    ServiceOperation = 'serviceOperation',
    BikeRent = 'bikeRent',
    OrderCharge = 'orderCharge',
}

export interface ServiceAttributes {
    id: number;          // shared
    type: ServiceType;   // shared
    duration?: number;   // only ServiceOperation
    rentedBike?: string; // only BikeRent
    orderType?: string;  // only OrderCharge
}

const badService: ServiceAttributes = {
    id: 2,
    type: ServiceType.ServiceOperation,
}
// is valid

😺 Inheritance based on enum value

interface ServiceBase {
    id: number;
    type: ServiceType;
}
interface ServiceOperation extends ServiceBase {
    type: ServiceType.ServiceOperation;
    duration: number;
}
interface BikeRent extends ServiceBase {
    type: ServiceType.BikeRent;
    rentedBike: string;
}
interface OrderCharge extends ServiceBase {
    type: ServiceType.OrderCharge;
    orderType: string;
}

type ServiceAttributes = ServiceOperation | BikeRent | OrderCharge;

const badService: ServiceAttributes = {
    id: 2,
    type: ServiceType.ServiceOperation,
}
  • Type '{ id: number; type: ServiceType.ServiceOperation; }' is not assignable to type 'ServiceAttributes'.
  • Type '{ id: number; type: ServiceType.ServiceOperation; }' is not assignable to type 'ServiceOperation'.
  • Property 'duration' is missing in type '{ id: number; type: ServiceType.ServiceOperation; }'.

😻 Type inference in control flow

let service: ServiceAttributes;

Conditions (total)

if (service.type === ServiceType.ServiceOperation) {
    service // let service: ServiceOperation
} else if (service.type === ServiceType.BikeRent) {
    service // let service: BikeRent
} else {
    service // let service: OrderCharge
}

Conditions (partial)

if (service.type === ServiceType.ServiceOperation) {
    service // let service: ServiceOperation
} else {
    service // let service:  BikeRent | OrderCharge
}

Switch-case

switch (service.type) {
    case ServiceType.ServiceOperation: {
        service // let service: ServiceOperation
        break;
    }
    default: {
        service // let service: BikeRent | OrderCharge
    }
}

Non-imperative 😾

const isOperation = (service: ServiceAttributes) => service.type === ServiceType.ServiceOperation;
if (isOperation(service)) {
    service // let service: ServiceAttributes
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment