简体   繁体   中英

Generics in Typescript: Passing generics in Functions

My typescript code like below: (within typescript 4.4)

export function convert<T extends (...args: any[]) => any>(
    func: T
): (_this: ThisParameterType<T>, ...args: OmitThisParameter<Parameters<T>>) => ReturnType<T> {
    return Function.call.bind(
        Function.bind,
        Function.call
    )(func) as (_this: ThisParameterType<T>, ...args: OmitThisParameter<Parameters<T>>) => ReturnType<T>;
}

but when i use it like this:

// mark 1
const arrayShift = convert([].shift);
// expect: const shifted: string
const shifted = arrayShift(["1"]); // const shifted: undefined

// mark 2
const arrayMap = convert([].map);
// expect (parameter) e: string
arrayMap(["1"], (e) => { // (parameter) e: never
    return parseInt(e, 10);
});

How to got expected type with modify the function named 'convert'?

I managed to achieve it with a 2-step approach. The convert returns a function, which you can call, with or without arguments.

see playground

function convert<A extends Array<T>, T extends any, K extends keyof Array<T>>(
  array: A extends Array<infer U> ? Array<U> : Array<T>,
  key: K,
) {
  function convertArray<A extends Array<T>, T extends any>(
    array: A extends Array<infer U> ? Array<U> : Array<T>,
    key: K,
  ) {
    return array[key]
  }
  return function<S extends Array<Y>, Y extends any>(
    subjectedArray: S extends Array<infer SK> ? Array<SK> : Array<Y>,
    args?: any[] // not yet figured out to call convertArray with args and keep types
  ) {
    return (convertArray<S, Y>(
      subjectedArray,
      key
    ))
  }
}

const arrayShift = convert([], 'shift')
const arrayMap = convert([], 'map')

const empty = arrayShift([])() // const empty: undefined
const shifted = arrayShift(["123"])() // const shifted: string | undefined
const mapped = arrayMap(["1"])(e => { // (parameter) e: string
  return parseInt(e, 10);
}) // const mapped: number[]

type Car = {
  engine: 'petrol' | 'gasoline'
}
const cars: Car[] = []
const emptyCars = arrayShift(cars)() // const emptyCars: Car | undefined

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM