Skip to content

Instantly share code, notes, and snippets.

@joemaidman
Last active October 6, 2021 16:32
Show Gist options
  • Save joemaidman/cbc38b1f6474532d616b53f46c58274b to your computer and use it in GitHub Desktop.
Save joemaidman/cbc38b1f6474532d616b53f46c58274b to your computer and use it in GitHub Desktop.
Type issue
// using TS V3.7.5
type ClassType<T> = new () => T;
class DefaultClass {}
class RedClass {}
class OrangeClass {}
class GreenClass {}
const enum MyEnum {
RED = 'RED',
ORANGE = 'ORANGE',
GREEN = 'GREEN',
}
const getColour = (): MyEnum => {
// just an example, could be any of the enum values (in reality comes from a request)
return MyEnum.GREEN;
};
const myFunction = <T, S>(defaultClassType: ClassType<T>, overrides: { colour: MyEnum; classType: ClassType<S> }[]) => {
const colour = getColour();
const colourOverride = overrides.find(or => or.colour === colour);
if (colourOverride) {
return new colourOverride.classType();
} else {
return new defaultClassType();
}
};
// Query: this infers the type of instance as 'DefaultClass | GreenClass' but we want it to be 'DefaultClass | RedClass | OrangeClass | GreenClass'
const instance = myFunction(DefaultClass, [
{ colour: MyEnum.RED, classType: RedClass },
{ colour: MyEnum.ORANGE, classType: OrangeClass },
{ colour: MyEnum.GREEN, classType: GreenClass },
]);
@OliverJAsh
Copy link

type ClassType<T> = new () => T;

class DefaultClass {}

class RedClass {}

class OrangeClass {}

class GreenClass {}

const enum MyEnum {
    RED = 'RED',
    ORANGE = 'ORANGE',
    GREEN = 'GREEN',
}

const getColour = (): MyEnum => {
    // just an example, could be any of the enum values (in reality comes from a request)
    return MyEnum.GREEN;
};

const myFunction = <
    T,
    O extends Array<{ colour: MyEnum; classType: ClassType<unknown> }>,
>(
    defaultClassType: ClassType<T>,
    overrides: O,
): T | InstanceType<O[number]['classType']> => {
    const colour = getColour();
    const colourOverride = overrides.find((or) => or.colour === colour);

    if (colourOverride) {
        return new colourOverride.classType() as InstanceType<
            O[number]['classType']
        >;
    } else {
        return new defaultClassType();
    }
};

const instance = myFunction(DefaultClass, [
    { colour: MyEnum.RED, classType: RedClass },
    { colour: MyEnum.ORANGE, classType: OrangeClass },
    { colour: MyEnum.GREEN, classType: GreenClass },
]);

@joemaidman
Copy link
Author

@OliverJAsh 🙏 thank you this is amazing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment