'Infer return type of function that takes a discriminated union?

I have a function that takes in an object that uses a discriminated union that returns a different structure based on that property.

While i could write an assertion isLicenseType fn, I was wondering if there is a way I could infer this based on the type argument provided to the fn, possibly with an assertion signature?

const licenseTypeMap: Record<string, LicenseOptions> = { abc: { ... } }
const siteIdMap: Record<number, SiteIdOptions> = { 12: { ... } }

type DynamicReferenceType =
    | { type: 'LICENSE'; licenseName?: string; }
    | { type: 'SITE_ID'; siteId?: number; };

export function getDynamicSchema(args: DynamicReferenceType) {
    if (args.type === 'LICENSE') {
        return licenseTypeMap[args.licenseName];
    }
    return siteIdMap[args.siteId];
}

const schema = getDynamicSchema({ type: 'license', licenseName: 'abc' })
// schema is of LicenseOptions | SiteIdOptions


Solution 1:[1]

Came across a solution that's as close as I'm going to get it seems. TS can't narrow the type of generic parameters, so there's a little bit of a casting required but:

const licenseTypeMap: Record<string, LicenseOptions> = { abc: { ... } }
const siteIdMap: Record<number, SiteIdOptions> = { 12: { ... } }

type DynamicReferenceType =
    | { type: 'LICENSE'; licenseName?: string; }
    | { type: 'SITE_ID'; siteId?: number; };

type ReturnTypeLookup = {
    LICENSE: LicenseOptions;
    SITE_ID: SiteIdOptions;
};

type SchemaFor<T extends DynamicReferenceType> = ReturnTypeLookup[T['type']];

export function getDynamicComponent<T extends DynamicReferenceType>(args: T): SchemaFor<T> {
    if (args.type === 'LICENSE') {
        return licenseTypeMap[args.licenseName] as SchemaFor<T>;
    }
    return siteIdMap[args.siteId] as SchemaFor<T>;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 joshuaaron