0

Looking at the type definitions of ngrx's ActionCreator, it looks like this:

export declare type ActionCreator<T extends string = string, C extends Creator = Creator> = C & TypedAction<T>;

here TypedAction is defined as:

export interface Action { type: string; }
export declare interface TypedAction<T extends string> extends Action { readonly type: T; }

And finally Creator:

export declare type FunctionWithParametersType<P extends unknown[], R = void> = (...args: P) => R;
export declare type Creator<P extends any[] = any[], R extends object = object> = FunctionWithParametersType<P, R>;

In a simplified form, ActionCreator is defined as an intersection:

C & TypedAction<T>

If C is a function (Creator)

(...args: P) => R;

and TypedAction is defined as

{ type: string; }

How can this be instantiated? :

(...args: P) => R & { type: string; }

I've trouble understanding the concept of an intersection of a function and a type. Could someone please shed some light on it?

More specifically I'm trying to create an instance of ActionCreator without using the 'createAction' function (for learning purposes), but so far with no success. What should the right-hand side in this example look like to make it work?:

const ac: ActionCreator<string, () => ({ b: number, type: string })> = ([]) => ({ b: 1, type: 'abc' });

The error is:

Type '([]: Iterable<any>) => { b: number; type: string; }' is not assignable to type 'ActionCreator<string, () => { b: number; type: string; }>'.
Type '([]: Iterable<any>) => { b: number; type: string; }' is not assignable to type '() => { b: number; type: string; }'.
Wolf359
  • 2,620
  • 4
  • 42
  • 62
  • 2
    `((...args: P) => R) & { type: string; }` is what you need to write. Note the use of parentheses around the function type which are necessary to specify that you were intersecting function types themselves and not their return types. – Aluan Haddad Mar 15 '21 at 20:51
  • @AluanHaddad if type A = {a: string}, type B = {b: string} and type C = A & B; then type C could be written as { a: string, b: string}. Could you please write your anser without using '&'? – Wolf359 Mar 15 '21 at 20:56
  • Sorry, I'm probably misunderstanding something. What you said is true for the given `A`, `B`, and `C` but I'm not understanding how it relates to your question. I don't have an answer I was just remarking that, without parenthesis around the function type, the intersection is with the return type – Aluan Haddad Mar 15 '21 at 20:59
  • 2
    Behind the scenes, functions in Javascript are actually objects! So a function can include arbitrary properties. This answer should help: https://stackoverflow.com/a/20734003/10431574 – Linda Paiste Mar 15 '21 at 21:19

1 Answers1

1

Functions are objects too, so they can have properties. Your instance would look like this

const result = ([]) => ({ b: 1});
result.type = "test";
const ac: ActionCreator<string, ([]) => {b: number}> = result;

playgound

Mirco S.
  • 2,510
  • 4
  • 13
  • Reading your answer and also inspecting ngrx source code for creatorAction function it's clear now. Thanks! – Wolf359 Mar 15 '21 at 21:35