Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to do this type-safely: "the types 'Vehicle<C>' and 'Vehicle<CarConfig>' have no overlap"

This code (which is weird, but I did it only to pose this question):

interface Vehicle<C> {
    id: string
    name: string
    config: C | null
}

interface CarConfig {
    leatherSeats: boolean
}

const Car: Vehicle<CarConfig> = {
    id: "car",
    name: "car",
    config: null
}

interface TruckConfig {
    numberOfWheels: number
}

const Truck: Vehicle<TruckConfig> = {
    id: "truck",
    name: "truck",
    config: null
}

function getVehicleConfig<C>(vehicle: Vehicle<C>): C | null {
    if (vehicle === Car) {
        return vehicle.config
    }
    if (vehicle === Truck) {
        return vehicle.config
    }
    throw new Error("Unknown vehicle")
}

Compiles with this error:

src/explain.ts:28:9 - error TS2367: This condition will always return 'false' since the types 'Vehicle<C>' and 'Vehicle<CarConfig>' have no overlap.

The expectation here is that (due to constraints in another part of the software) vehicle in getVehicleConfig will always be either the Car object or the Truck object, and getVehicleConfig will return the config associated with the instance.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

What is the right way to express getVehicleConfig in a type safe manner?

>Solution :

The way to go would be a discriminated union :

type VehiculeType= 'Car' | 'Truck';


interface Vehicle<C> {
    id: string
    name: string
    config: C | null
    type: VehiculeType;
}

interface CarConfig {
    leatherSeats: boolean
}

const Car: Vehicle<CarConfig> = {
    type: 'Car',
    id: "car",
    name: "car",
    config: null
}

interface TruckConfig {
    numberOfWheels: number
}

const Truck: Vehicle<TruckConfig> = {
    type: 'Truck',
    id: "truck",
    name: "truck",
    config: null
}

function getVehicleConfig<C>(vehicle: Vehicle<C>): C | null {
    if (vehicle.type === 'Car') {
        return vehicle.config
    }
    if (vehicle.type === 'Truck') {
        return vehicle.config
    }
    throw new Error("Unknown vehicle") 
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading