How do you define an array of generics in TypeScript?

后端 未结 2 523
礼貌的吻别
礼貌的吻别 2021-02-13 10:36

Let\'s say I have a generic interface like the following:

interface Transform {
    transformer: (input: string, arg: ArgType) => string;
    a         


        
2条回答
  •  梦谈多话
    2021-02-13 10:46

    You can do this using the generic tuple rest parameters (added in TS 3.0).

    type TransformRest = {
       [P in keyof T]: T[P] extends T[number] ? Transform : never
    }
    
    function applyTransforms(input: string, ...transforms: TransformRest): string {
       for (const transform of transforms) {
          input = transform.transformer(input, transform.arg);
       }
    
       return input;
    }
    
    // Makes a tuple from it's arguments, otherwise typescript always types as array
    function tuplify(...args: TS) {
       return args;
    }
    
    // Use like this:
    const transforms = tuplify(
       {
          transformer: append,
          arg: " END"
       },
       {
          transformer: repeat,
          arg: 4
       },
    );
    
    //And call apply transforms like this:
    applyTransforms("string", ...transforms)
    
    //or like this:
    applyTransforms("string", transform1, transform2)
    

    Explanation

    Typescript has really powerful type inference, but usually chooses the loosest types it can. In this case you need to force it to think of your transforms as a Tuple so that each element has it's own type, and then let the inference do the rest.

    I did this with mapped types, the one hiccup with this is that Typescript will use all the tuple keys (such as "length"), not just the numeric ones. You just need to force it to only map the numeric ones. Hence the condition: T[P] extends T[number]

提交回复
热议问题