Home > Net >  Typescript type check a methods second parameter based on first choice
Typescript type check a methods second parameter based on first choice

Time:10-07

Take a look at the request methods' params in this class

export type SDKmodules =  'orders' |'pricing' |'catalogV2' |'catalog' |'prodType' |'reports' |'listings';

export class SellerAPI {
    request(mod: SDKmodules, method: string, params: any = {}) {
        return this.http.get<any>( `/sp-sdk/${mod}/${method}`, { params });
    }
}

I am trying to type the request parameters based on the chosen module. Each module is a class. Here is a simplified down view.

{
    orders: ['getOrder', 'getOrderExt', 'getOrderItems', 'saveOrders'],
    pricing: ["getCompetitivePricing", "getItemOffers", "getListingOffers", "getPricing"],
    catalogV2: ["getCatalogItem", "searchCatalogItems", "getCatalogProdType"],
}

so if the module choice was orders then the only acceptable method would be...

'getOrder', 'getOrderExt', 'getOrderItems', 'saveOrders'

Im looking for the most appropriate way to type this method. even if it means undoing any part of the sample code above.

Here are somethings i think might work.

  • Multiple overloads for the request method
  • Because all of the "modules" (the parameter) are class objects. Is there a way to use the modules them selves to type this method?

Im pretty new to typescript. Thank you in advance.

CodePudding user response:

NOTE: This question answers the original revision of the question

Here's one way that can be achieved by extracting the type from the moduleMethods constant (defined below), which has a const assertion:

export type SDKmodules = 'orders' | 'pricing' | 'catalogV2'; 
    // | 'catalog' | 'prodType' | 'reports' | 'listings';

const moduleMethods = {
    orders: [
        'getOrder', 'getOrderExt', 'getOrderItems', 'saveOrders'],
    pricing: [
        "getCompetitivePricing", "getItemOffers", "getListingOffers", "getPricing"],
    catalogV2: [
        "getCatalogItem", "searchCatalogItems", "getCatalogProdType"],
} as const;

type OrderType<T extends SDKmodules> = (typeof moduleMethods)[T][number]

export class SellerAPI {
    request<T extends SDKmodules>(mod: T, method: OrderType<T>, params: any = {}) {
        return console.log(`/sp-sdk/${mod}/${method}`, { params });
    }
}

const api = new SellerAPI()
api.request("orders", "getOrderItems")

You could even take it one step further, and infer the type of SDKModules from moduleMethods with:

type SDKModules = keyof typeof moduleMethods;

so that the moduleMethods object becomes your one source of truth.

Playground link

  • Related