Understanding Function Declaration Javascript

Viewed 53

I am trying to understand function declaration in Javascript in RXJS Library. I am trying to understand how the function is declared.

https://rxjs.dev/api/index/function/scan

scan<V, A, S>(accumulator: (acc: V | A | S, value: V, index: number) => A, seed?: S): OperatorFunction<V, V | A>

My understanding

1.scan takes three arguments <V, A, S>

2.return OperatorFunction<V, V | A>]

3.Seed is optional [ seed?: S ]

but i am not able to understand what does below mean

(accumulator: (acc: V | A | S, value: V, index: number) => A, seed?: S)

Why do we need word

accumulator:

and what does below mean, why do we need an arrow function

=> A, seed?: S

It should be declared like scan<V, A, S>(acc: V | A | S, value: V, index: number)): OperatorFunction<V, V | A>

Please throw some light.

1 Answers

Understanding the type signature of RxJS' scan operator

function scan<V, A, S>(
  accumulator: (acc: V | A | S, value: V, index: number) => A, 
  seed?: S
): OperatorFunction<V, V | A>

This should be read as follows, scan is a function with 2 parameters.

  • The first param is called accumulator and is itself a function too. * The second param is an optional parameter called seed.

scan returns an OperatorFunction

Consider this simple function:

function add(
  a:number, 
  b?: number
): number

This should be read as follows, add is a function with 2 parameters. The first param is called a and is a number. The second param is an optional parameter called b that may be a number.

add returns a number


Let's re-introduce generics and add a function as a parameter:

function processNumbers<T>(
  process: (x: number, y: number) => T,
  a: number,
  b: number
): T {
  // Implementation
  // Create out value of type T
  const processed: T = process(a*2, b-5);
  // Return a value of type T
  return processed;
}

processNumbers generic type T gets specialized to a concrete type (string or ProcNum as examples) when invoked:

// Let's call processNumbers with some arguments
// the processed value will be of type string in this case.
const processed1: string = processNumbers(
  (x,y) => `Result: ${(x / 2) + (y * 2)}`,
  23,
  29
);
// Display our string
console.log(processed1) // Result: 71

// lets call it again with different first argument.
// Instead of a string, we'll process some wrapper type
interface ProcNum{
  num: number
}

// The processed value will be of type ProcNum in this case.
const processed2: ProcNum = processNumbers(
  (x,y) => ({num: (x / 2) + (y * 2)}),
  23,
  29
);
// Display our string
console.log(processed2) // {num: 71}

This reads as: processNumbers is a function that is generic over any type T. It has 3 parameters.

The first parameter is called process and it's type is a function that takes two numbers and returns a value of type T.

The other two parameters are called a and b and are simple numbers.

Finally, processNumbers returns the same type of value that process returns.

When we first invoked processNumbers with 3 arguments, the generic type for the function was specialized as a string. Because the arrow function returned a string, that meant the entire function returned a string. You can see why from the implementation.

The second time we invoked processNumbers, it was specialized with ProcNum.


A quick aside:

TypeScript didn't do the best job with it's type signatures. When you see something like variableName: blahblah, that can be either a TypeScript type signature OR it can be Vanilla JavaScript's property initialization.

You should be able to tell from context. Object properties are always part of objects (surrounded by these {} like {a:1, b:2}) and always initialized by an expression. Everything else is a type signature

Here's both on one line:

const var: {a:number, b:number} = {a:1, b:2};
Related