Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to reference all parameters except first in typescript

Tags:

typescript

I would like to reference one function's parameter types in another function, but only use a subset of them.

//params of bar should be same as foo, except p1 should be a different type

function foo(p1: string, p2: number, p3: boolean){
 ...
}

//i'd like to do something like this, though it's obviously not valid syntax
function bar(p1: string[], ...rest: Parameters<typeof foo>.slice(1)){
}

Is there a way to do that? Obviously it's not hard to do manually with only 3 parameters, but in my actual code I have more parameters and I'd like to not repeat them.

like image 464
bdwain Avatar asked Jul 21 '20 23:07

bdwain


2 Answers

TypeScript 4.0 +

Option 1: Variadic tuple

type DropFirst<T extends unknown[]> = T extends [any, ...infer U] ? U : never

function bar(p1: string[], ...rest: DropFirst<Parameters<typeof foo>>) { }
// bar: (p1: string[], p2: number, p3: boolean) => void

Syntax for inferring all tuple elements except the first one now has become simpler. See Robby Cornelissen's answer for versions < 4.0.

Option 2: Labeled Tuple Elements

type CommonParams = [p2: number, p3: boolean];

function foo2(p1: string, ...rest: CommonParams){} 
// foo2: (p1: string, p2: number, p3: boolean) => void
function bar2(p1: string[], ...rest: CommonParams) { }
// bar2: (p1: string[], p2: number, p3: boolean) => void

Named tuples can be used to preserve function parameter names, so there is no lossy conversion.

Playground

like image 112
ford04 Avatar answered Oct 16 '22 11:10

ford04


You can create a type tuple using the Parameters utility type, and then create a new type from that, omitting the first type:

type Rest<T extends any[]> = 
  ((...p: T) => void) extends ((p1: infer P1, ...rest: infer R) => void) ? R : never;

function foo(p1: string, p2: number, p3: boolean) {
}

function bar(p1: string[], ...rest: Rest<Parameters<typeof foo>>) {
}


bar([''], 0, true); // ok
bar('', 0, true); // error
bar([''], true, 0); // error

See also this answer.

like image 27
Robby Cornelissen Avatar answered Oct 16 '22 10:10

Robby Cornelissen