简体   繁体   中英

Typescript - Use element in array argument as return type

I have a simple function as follow:

const transform = ([a, b]) => ({operation: a, ...b});

How can I type this function to make sure the return type is an object containing a key operation with the type of the argument a and the property of b.

I tried the following but without success:

function transform<[A, B]>(param: [A, B]): { operation: A } & B {
    return { operation: param[0], ...param[1] };
}

Any help about that? Thanks!

You have what amounts to a typographical error; instead of transform<[A, B]>(...) , you need to write transform<A, B>(...) like this:

function transform<A, B>(param: [A, B]): { operation: A } & B {
  //        ----> ^^^^^^         ^  ^  <------------> ^     ^
  // declaring type params         using the type params
  // 
  return { operation: param[0], ...param[1] };
}

The transform() function is generic in two type parameters A , and B . (You can think of these almost like regular function parameters, but instead of corresponding to arguments that callers pass in as values , they are arguments that callers pass in as types .) The syntax for declaring the list of type parameters a generic function takes is to put a comma-separated list of these parameters inside angle brackets, immediately before the list of regular parameters in parentheses.

It's only later in the function signature and implementation where you use the type parameters as types. So the param function parameter is annotated as type [A, B] , a tuple type where the first element is of type A and the second element is of type B . The fact that you were going to use the type [A, B] has nothing to do with the syntax to declare the type parameters.

That's the answer to the question as asked.


I could go a little further and suggest that a more direct translation of your original transform JavaScript code into TypeScript would look like this:

const transform = <A, B extends object>(
  [a, b]: [A, B]
): { operation: A } & B => ({ operation: a, ...b });

Here you can see that even arrow functions can be generic, and therefore need a type parameter declaration before the parameter list (which must be in parentheses, even if your arrow function looks like x => x ... you can't write <T>x:T => x , you need <T>(x: T) => x ). Also see that the return type annotation of an arrow function comes immediately after the parameter list with a colon, and before the arrow => .

Since you are going to use object spread on b which of type B , it's useful to tell the compiler that B should be constrained to the object type , so that nobody calls transform([1, 2]) and is possibly confused by what comes out.

Also, you can still use destructuring assignment in your function parameter, so we have ([a, b]: [A, B]) instead of (param: [A, B]) .

Playground link to code

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