简体   繁体   中英

How Can I Map a New Type to an Element of a Tuple Type using a TypeScript Definition File?

I have a function signature imported from a third party library. I have a declaration file ( node-api.d.ts ) that I'd like to add a new type into which changes the type of one of the parameters to the function based off the imported function so that I catch any changes by the third-party lib author to their signature, like so:

type ImportedMethod = (
  this: void,
  extension: object,
  otherParams: any
) => void

type ChangedMethod = (
  this: void,
  extension: MyExtensionType,
  otherParams: any
) => void

I think the way to do this is to use the Parameters utility function and get a tuple type (is that the correct term?) of the parameters, modify the type of the element I'm interested in, and then spread that new tuple type in a new function signature:

// [extension: object, otherParams: any]
type Params = Parameters<ImportedMethod>

// @TODO: Figure out how to transform the `extension`
// element's type of my "tuple type" to a new type

type ChangedMethod = (
  ...args: ModifiedParams
) => void

I can't figure out how to change the type of an element of the tuple type . I think I need to use mapped and conditional types, but I'm not sure how to introduce the string literal as a condition:

type SwapExtensionElement<T> = {
  [K in keyof T]: K extends 'extension' ? MyExtensionType : T[K]
}

type ModifiedParams = SwapExtensionElement<ImportedMethod>
// [extension: object, otherParams: any]

I'd sure appreciate any help.

If you know the position, you can infer parts of the parameters tuple, and the reassemble new parameters.

In this case you need everything but the first paramter, since that one is getting replaced. So let's use a utility type called Tail :

type Tail<T extends unknown[]> =
    T extends [infer _, ...infer Rest] ? Rest : never

type Test = Tail<[1, 2, 3]> // [2, 3]

This takes a tuple and pulls out the first element to an ignored type _ , and everything after into Rest and then resolves to Rest .

You can then create your method type like this:

type ChangedMethod = (
  this: void,
  extension: MyExtensionType,
  ...args: Tail<Params>
) => void

The IDE then reports the type of ChangedMethod as:

type ChangedMethod = (this: void, extension: MyExtensionType, otherParams: any) => void

Playground

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