Search code examples
typescriptfactory-pattern

Typescript variable can be either type


I have a packageMessage factory function, and i need it to return one of two types: PackagedChannel or PackagedGuildChannel based on the value of a type parameter.

The function:

function packageMessage(id: string, type: PackagedChannelType, name?: string, position?: number): PackagedChannel | PackagedGuildChannel {
    var packaged: PackagedChannel | PackagedGuildChannel;
    packaged.id = id;
    packaged.type = type;
    if (type === 'text') {
        packaged.name = name;
        packaged.position = position;
    }
    return packaged;
}

The types:

type PackagedChannelType = 'dm' | 'text' | 'unknown';
interface PackagedChannel {
    id: string;
    type: PackagedChannelType;
}
interface PackagedGuildChannel extends PackagedChannel {
    name: string;
    position: number;
}

however, the function yields a Property 'name/position' does not exist on type 'PackagedChannel' error.

How could i do this? help would be very much appreciated :)


Solution

  • function packageMessage(id: string, type: PackagedChannelType, name?: string, position?: number): PackagedChannel | PackagedGuildChannel {
        return type === 'text' ? { id, type, name, position } : { id, type};
    }
    

    Or even better, if you want more type safety, you may overload it.

    function packageMessage(id: string, type: 'text', name: string, position: number): PackagedGuildChannel
    
    function packageMessage(id: string, type: 'dm' | 'unknown'): PackagedChannel
    
    function packageMessage(id: string, type: PackagedChannelType, name?: string, position?: number): PackagedChannel | PackagedGuildChannel
    
    function packageMessage(id: string, type: PackagedChannelType, name?: string, position?: number): PackagedChannel | PackagedGuildChannel {
        return type === 'text' ? { id, type, name, position } : { id, type };
    }