Cannot find name when using action as type in method
Silthus opened this issue ยท 5 comments
I am trying to use this awesome library with @ngxs/store. Everything works fine except the type signature on action methods. When trying to use a generated ts-action
action Typescript shows the compile time error: Cannot find name 'ActionName'
.
See this stackblitz as demo: https://stackblitz.com/edit/angular-azg9at
import { State, StateContext, Action, Selector } from '@ngxs/store';
import { action, payload } from 'ts-action';
export const CreateModelAction = action('[App] CREATE MODEL', payload<AppModel>());
export interface AppModel {
id: number;
name?: string;
}
export interface AppStateModel {
models: AppModel[];
}
const DEFAULT_STATE: AppStateModel = {
models: []
};
@State({
name: 'app',
defaults: DEFAULT_STATE
})
export class AppState {
@Selector()
static models(state: AppStateModel) {
return state.models;
}
@Action(CreateModelAction)
createModel(ctx: StateContext<AppStateModel>, action: CreateModelAction) { // <-- this is the error here
ctx.patchState({
models: [
...ctx.getState().models,
action.payload
]
})
}
}
The actions created by the action
function are classes/constructors that are created at runtime, so there is no corresponding TypeScript type.
To use the action where you'd usually use a TypeScript type, you will need to do what's done in the README with reducer parameters. That is, you'll need to use union
and typeof
, like this:
import { action, payload, union } from 'ts-action';
...
export const CreateModelAction = action('[App] CREATE MODEL', payload<AppModel>());
const CreateModelActionUnion = union({ CreateModelAction });
export type CreateModelActionType = typeof CreateModelActionUnion;
...
@Action(CreateModelAction)
createModel(ctx: StateContext<AppStateModel>, action: CreateModelActionType) { ... }
union
is implemented using an internal/undocumented action
property on the constructor, so that would be the safest way to go. You could also use the action
property directly, but it's possible that might be removed if/when I update the package to support a minimum TypeScript version of 2.8 (that version has a bunch of new features that should simplify the implementation of ts-action
):
export const CreateModelAction = action('[App] CREATE MODEL', payload<AppModel>());
export type CreateModelActionType = typeof CreateModelActionUnion.action;
Actually, if you are using TypeScript 2.8, the best way to solve the problem is with the new, built-in InstanceType
type:
export const CreateModelAction = action('[App] CREATE MODEL', payload<AppModel>());
export type CreateModelActionType = InstanceType<typeof CreateModelActionUnion>;
...
@Action(CreateModelAction)
createModel(ctx: StateContext<AppStateModel>, action: CreateModelActionType) { ... }
Would it be possible to make action
return the InstanceType
so it would only require one single line to make it all work?
I don't think so, action
has to return a constructor - not the constructed type.
Anyway, there are some things that are much easier now, with TypeScript 2.8, so revisiting the implementation is on my todo list (to which I'll add a reference to your question). It's quite likely there will be some simplification (and breaking changes).
Closing this. I'll revisit your question when I get around to the TypeScript 2.8 refactor.