0

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.

Omar
  • 2,726
  • 2
  • 32
  • 65

1 Answers1

2

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

spender
  • 117,338
  • 33
  • 229
  • 351
  • Wow thank you for the time you spent writing that. I updated my question to include my version of "moduleMethods" instead of the other sample object. Im working in a mono repo. We cant import moduleMethods into the frontend cause its nodejs only. Do you know how to import it for type use only? if there is a way then i can use the ideal version of ur answer. Im open to changing everything to satisfy one place maintenance for this method – Omar Oct 06 '21 at 17:01
  • Or instead do you recommend that i just maintain module methods as a simple object like the one in your answer? That doesnt sound 'wrong'. – Omar Oct 06 '21 at 17:06