Home > Mobile >  How to modify the type of a value of a constant object type # typescript
How to modify the type of a value of a constant object type # typescript

Time:11-25

I have a constant object type whose value type is a function. I want to get another constant object type through this type, and change the return value type of the function to Promise type .

const CONST_METHOD_MAP = {
  ready: (str: string) => str,
  b: (num: number) => num,
  c: () => Promise.resolve(1)
} as const

want

type CONST_METHOD_MAP: {
    readonly ready: (str: string) => Promise<string>;
    readonly b: (num: number) => Promise<number>;
    readonly c: () => Promise<number>;
}
type MyType<K extends keyof CONST_METHOD_MAP = keyof typeof CONST_METHOD_MAP> =
  {
    [k in K]: (
      ...args: Parameters<CONST_METHOD_MAP[K]>
    ) => Promise<ReturnType<CONST_METHOD_MAP[K]>>
  }

// an array containing workers created according to navigator.hardwareConcurrency
const workerStore = [
  {
    worker: new Worker(new URL('./worker0.ts', import.meta.url), {
      type: 'module'
    }),
    syncTaskCount: 0
  },
  {
    worker: new Worker(new URL('./worker1.ts', import.meta.url), {
      type: 'module'
    }),
    syncTaskCount: 1
  },
  // ...more worker
]
// I will follow CONST_ METHOD_ MAP constructs a set of functions that call web worker execution logic
const funcMap = {
  ready: (...args: Parameters<typeof CONST_METHOD_MAP['ready']>) => {
    const promise = new Promise<ReturnType<typeof CONST_METHOD_MAP['ready']>>(
      resolove => {
        const worker = takeWorker().worker // take a worker who is not executing synchronization function
        const hander = (
          e: MessageEvent<{
            key: 'ready'
            res: ReturnType<typeof CONST_METHOD_MAP['ready']>
            traceId: number
            type: 'resolve' | 'setup'
          }>
        ) => {
          if (e.data.traceId !== traceId) {
            return
          } else if (e.data.type === 'resolve') {
            resolove(e.data.res)
            worker.removeEventListener('message', hander)
          } else if (e.data.type === 'setup') {
            workerStore.find(item => item.worker === worker)?.syncTaskCount--
          }
        }
        worker.addEventListener('message', hander)
        worker.postMessage({ key: 'ready', args: args, traceId: 123456789 })
      }
    )
    return promise
  },
  b: (
    ...args: Parameters<typeof CONST_METHOD_MAP['b']>
  ): Promise<ReturnType<typeof CONST_METHOD_MAP['b']>> => {
    // ...
  },
  c: (
    ...args: Parameters<typeof CONST_METHOD_MAP['c']>
  ): Promise<ReturnType<typeof CONST_METHOD_MAP['c']>> => {
    // ...
  }
} as MyType
const res = funcMap.ready()
/**
The res type derived by typescript is const res: Promise<string | number | Promise<number>>

The res type I expect is Promise<string>
*/

The reason is that I want to convert some functions into web worker functions, so CONST_ METHOD_ MAP is a collection of synchronization functions that I configure and want to convert to web workers. So the content of my funcMap value is to call the function of the web worker, so its return value will change from synchronous to asynchronous. Then because my funcMap is generated from a constant object, its type should also be a constant type

I want to build a constant object type. When I call my funcMap Ready(), I want funcMap The parameter type of ready is Parameters<typeof CONST_ METHOD_ MAP ['ready']>, not Parameters<typeof CONST_ METHOD_ MAP [keyof typeof CONST_METHOD_MAP]>, and since this function will use the web worker to execute logic, its return value is asynchronous. I hope funcMap The return value type of ready is Promise<ReturnType<CONST_ METHOD_ MAP ['ready']>>instead of Promise<ReturnType<CONST_ METHOD_ MAP[keyof typeof CONST_METHOD_MAP]>>

CodePudding user response:

CONST_METHOD_MAP is a constant, not a type, using it as a type will not work without typeof

So what you need to do is use typeof whenever you use CONST_METHOD_MAP and also you're using K (uppercase), that is why your type is not correct, use lowercase k and it will work

const CONST_METHOD_MAP = {
  ready: (str: string) => str,
  b: (num: number) => num,
  c: () => Promise.resolve(1)
} as const

type MyType<K extends keyof typeof CONST_METHOD_MAP = keyof typeof CONST_METHOD_MAP> =
  {
    [k in K]: (
      ...args: Parameters<typeof CONST_METHOD_MAP[k]> // You were using uppercase K here
    ) => Promise<ReturnType<typeof CONST_METHOD_MAP[k]>> // and here
  }

const funcMap = {} as MyType
const res = funcMap.ready() 
  • Related