question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TypeScript helpers suggestion.

See original GitHub issue

Hello,

I have used feathers-vuex with TypeScript in a project and I made a set of helpers that I think could be really useful to other developers, here you can see the source code and below is an example of usage:


import Vue from 'vue'
import { Component } from 'vue-property-decorator'
import { namespace, Action } from 'vuex-class'
import { ActionGet, ActionCreate, ActionPatch } from '../types/feathers'
import { Person } from '../types/models'

const PeopleAction = namespace('people', Action)

@Component
export default class CreateEditPeople extends Vue {
  @PeopleAction('get') getPerson: ActionGet<Person>
  @PeopleAction('create') createPerson: ActionCreate<Person>
  @PeopleAction('patch') patchPerson: ActionPatch<Person>
  // some extra here
}

TypeScript reads it really well and all suggestions and autocomplete helps a lot.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:3
  • Comments:11 (8 by maintainers)

github_iconTop GitHub Comments

3reactions
NickBollescommented, Jul 30, 2019

I have some typings for feathers-vuex too, I’m planning on putting together a PR at some point, but for now here they are.

Updated 7/30/19


import { Application, Query, Params } from "@feathersjs/feathers";
import { StoreOptions, Plugin, Commit, Dispatch, Store } from "vuex";
import Vue, { PluginObject, ComponentOptions } from "vue";
import { Request } from "request";
import { PropsDefinition } from "vue/types/options";

/**
 * default export
 */
declare const FeathersVuexDefault: (client: Application, options: Partial<FeathersVuexOptions>) => FeathersVuexResult;
export default FeathersVuexDefault;

interface FeathersVuexResult {
  service<ModelType = any, IDType = string>(servicePath: string, options?: Partial<FeathersVuexOptions>): Plugin<FeathersVuexServiceState<ModelType, IDType>>;
  auth<UserType>(options?: FeathersVuexAuthOptions): Plugin<FeathersVuexAuthState<UserType>>;
  FeathersVuex: PluginObject<any>;
}

interface FeathersVuexCoreProps {
  /**
   * @default 'id'
   */
  idField: string;
  /**
   * @default false
   */
  autoRemove: boolean;
  /**
   * @default true
   */
  enableEvents: boolean;
  /**
   * @default false
   */
  addOnUpsert: boolean;
  /**
   * @default false
   */
  diffOnPatch: boolean;
  /**
   * @default false
   */
  skipRequestIfExists: boolean;
  /**
   * @default false
   */
  preferUpdate: boolean;
  /**
   * @default false
   */
  replaceItems: boolean;
}
interface FeathersVuexStoreOptions<Store> extends Pick<StoreOptions<Store>, 'state' | 'getters' | 'mutations' | 'actions'> { }

interface FeathersVuexOptions<Store = any> extends FeathersVuexStoreOptions<Store>, FeathersVuexCoreProps {

  /**
   * @default 'path'
   */
  nameStyle?: 'short' | 'path';
  namespace: string;
  apiPrefix: string
  modelName: string;
  instanceDefaults?: any;
  /**
   * @debug false
   */
  debug: boolean;
}

/**
 * Service Model
 */

// This is an interface because it needs to return FeathersVuexModelClass & T
// from the constructor, which isn't allowed with classes
interface FeathersVuexModelClass<ModelType = any> {
  namespace: string;
  className: string;
  modelName: string;
  store: Store<any>; // todo: Type the VuexStore so we can include it here
  options: FeathersVuexOptions;
  new(data?: Partial<ModelType>, options?: FeathersVuexModelOptions): FeathersVuexModel<ModelType>;
  create: (params?: GetParams) => Promise<FeathersVuexModel<ModelType>>;
  save: (params?: GetParams) => Promise<FeathersVuexModel<ModelType>>;
  patch: (params?: GetParams) => Promise<FeathersVuexModel<ModelType>>;
  update: (params?: GetParams) => Promise<FeathersVuexModel<ModelType>>;
  clone: () => Promise<FeathersVuexModel<ModelType>>;
  reset: () => Promise<FeathersVuexModel<ModelType>>;
  remove: (params?: GetParams) => Promise<FeathersVuexModel<ModelType>>;
}

export type FeathersVuexModel<T> = FeathersVuexModelClass<T> & T;

type GetParams = Exclude<Params, 'paginate'>;
type FindParams = Params;

interface FeathersVuexModelOptions {
  isClone?: boolean;
  skipCommit?: boolean;
}

interface ModelStatic<T> {
  new(data?: Partial<T>, options?: FeathersVuexModelOptions): FeathersVuexModel<T>;
  find: (params?: FindParams) => FeathersVuexModel<T>[];
  findInStore: (params?: FindParams) => FeathersVuexModel<T>[];
  get: (id: any, params?: GetParams) => FeathersVuexModel<T>[];
  getFromStore: (id: any, params?: GetParams) => FeathersVuexModel<T>[];
}

/**
 * Vue Plugin
 */
type FeathersVuexGlobalModelsIndex<T> = {
  [P in keyof T]: {
    new(data?: Partial<T[P]>, options?: FeathersVuexModelOptions): FeathersVuexModel<T[P]>;
    find: (params?: FindParams) => FeathersVuexModel<T[P]>[];
    findInStore: (params?: FindParams) => FeathersVuexModel<T[P]>[];
    get: (id: any, params?: GetParams) => FeathersVuexModel<T[P]>[];
    getFromStore: (id: any, params?: GetParams) => FeathersVuexModel<T[P]>[];
  }
}


// This doesn't work because merging this into a string signature isn't a valid type
// Leaving it here so that hopefully someone can figure it out in the future
// type FeathersVuexGlobalModelsByPath<T> = {
//   byServicePath: FeathersVuexGlobalModelsIndex<T>
// }

/**
 * @description The type for the $FeathersVuex vue plugin. To type this stronger include the
 * following in a typings.d.ts file
 *
 *
 * @example
 * declare module "vue/types/vue" {
 *   import { FeathersVuexGlobalModels } from "feathers-vuex";
 *   interface Vue {
 *     $FeathersVuex: FeathersVuexGlobalModels<Services>;
 *   }
 * }
 *
 * @description Where services is something like this
 * @example
 * interface Services {
 *   users: User
 *   //...
 * }
 *
 * interface User {
 *   name: string;
 *   rating: number;
 *   //...
 * }
 *
 */
export type FeathersVuexGlobalModels<T = any, P = any> = FeathersVuexGlobalModelsIndex<T> // & FeathersVuexGlobalModelsByPath<P>; // See comment above

/**
 * Add FeathersVuex to the Vue prototype
 */
declare module "vue/types/vue" {
  interface FeathersVuexPluginType extends FeathersVuexGlobalModels { }

  interface Vue {
    $FeathersVuex: FeathersVuexPluginType;
  }
}

/**
 * Auth module factory
 */
interface FeathersVuexAuthOptions<State = FeathersVuexAuthState> extends FeathersVuexStoreOptions<State> {
  userService: string
}

interface FeathersVuexAuthState<UserType = any> {
  accessToken?: string, // The JWT
  payload: Object, // The JWT payload

  isAuthenticatePending: boolean,
  isLogoutPending: boolean,

  errorOnAuthenticate: Error | undefined,
  errorOnLogout: Error | undefined,
  user: UserType
}

interface FeathersVuexServiceState<ModelType = any, IDType = string> extends FeathersVuexCoreProps {
  ids: IDType[],
  keyedById: {
    [i: string]: ModelType
  }, // A hash map, keyed by id of each item
  currentId?: IDType, // The id of the item marked as current
  copy?: ModelType, // A deep copy of the current item
  servicePath: string // The full service path
  paginate: boolean, // Indicates if pagination is enabled on the Feathers service.
  pagination: { [key: string]: ModelType[] }, // Indicates if pagination is enabled on the Feathers service.

  isFindPending: boolean,
  isGetPending: boolean,
  isCreatePending: boolean,
  isUpdatePending: boolean,
  isPatchPending: boolean,
  isRemovePending: boolean,

  errorOnfind: Error | undefined,
  errorOnGet: Error | undefined,
  errorOnCreate: Error | undefined,
  errorOnUpdate: Error | undefined,
  errorOnPatch: Error | undefined,
  errorOnRemove: Error | undefined
}

/**
 * Data Components
 */
// todo: use generic FeathersVuex*Computed
export const FeathersVuexFind: ComponentOptions<
  Vue,
  FeathersVuexFindData,
  FeathersVuexFindMethods,
  FeathersVuexFindComputed,
  PropsDefinition<FeathersVuexFindProps>,
  FeathersVuexFindProps>;

export const FeathersVuexGet: ComponentOptions<
  Vue,
  FeathersVuexGetData,
  FeathersVuexGetMethods,
  FeathersVuexGetComputed,
  PropsDefinition<FeathersVuexGetProps>,
  FeathersVuexGetProps>;

interface FeathersVuexFindData {
  isFindPending: boolean;
}

interface FeathersVuexGetMethods {
  findData(): Promise<void>;
  fetchData(): Promise<void>;
}

interface FeathersVuexFindComputed<T = any> {
  items: T[];
  scope: { [key: string]: any }
  pagination: { [key: string]: any }
}

interface FeathersVuexDataComponentProps {
  service: string;
  query?: any;
  queryWhen?: boolean | ((id: string, ...args: any[]) => boolean);
  fetchQuery: any;
  watch?: string | string[];
  local?: boolean;
  editScope?: (params: FeathersVuexEditScopeArgs) => { [key: string]: any };
}

interface FeathersVuexEditScopeArgs {
  item: any;
  isGetPending: boolean
}

interface FeathersVuexFindProps extends FeathersVuexDataComponentProps {
  qid?: string;
}

interface FeathersVuexGetData {
  isFindPending: boolean;
  isGetPending: boolean;
}
interface FeathersVuexFindMethods {
  getArgs(queryToUse?: Query): any[];
  getData(): Promise<void>;
  fetchData(): Promise<void>;
}
interface FeathersVuexGetComputed<T = any> {
  item: T | null;
  scope: { [key: string]: any }
}

interface FeathersVuexGetProps extends FeathersVuexDataComponentProps {
  id?: number | string;
}


/**
 * Utilities
 */
// todo: these mixins could probably have much better return types to make use of the generic
export function makeFindMixin<T = any>(options: MakeFindMixinOptions<T>): (ComponentOptions<Vue> | typeof Vue);
export function makeGetMixin<T = any>(options: MakeGetMixinOptions<T>): (ComponentOptions<Vue> | typeof Vue);

interface DataComponentOptions {
  /**
   * Service name, either service or name are required
   *
   * note: it looks like this can also be a function, but I don't quite understand the effects
   * so I'm not documenting it right now
   */
  service: string;
  /**
   * Service name, either service or name are required
   */
  name?: string;
  params?: Params;
  /**
   * @default () => true
   */
  queryWhen?: boolean | ((params: Params) => boolean);
  /**
   * @default false
   */
  local?: boolean;
  qid?: string | number | symbol;
  debug?: boolean;
  watch: string | boolean | string[];
}

interface MakeFindMixinOptions<T = any> extends DataComponentOptions {
  fetchQuery?: Query;
  items?: T[];
}
interface MakeGetMixinOptions<T = any> extends DataComponentOptions {
  fetchParams?: Params;
  id?: any;
  item?: T;
}


/**
 * Init Auth
 */
interface InitAuthOptions {
  commit: Commit;
  dispatch: Dispatch;
  req: Request;
  cookieName: string;
  moduleName: string;
  feathersClient: Application;
}
export function initAuth(options: InitAuthOptions): Promise<object>;


1reaction
marshallswaincommented, Jan 15, 2019

@rayfoss Thanks for the update. I have similar sentiment. If @nickmessing’s suggestions work without requiring modifying the repo, that’s the perfect solution, in my opinion.

I’ve added a link to this issue in the docs. I’m closing this issue, now. Thanks, guys.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Documentation - TypeScript 4.6
TypeScript now provides suggestions for when parameter names don't match between your function and its JSDoc comment. Suggestion diagnostics being shown in ...
Read more >
How to get suggestion in typescript with "type JustifyContent ...
This requires a trick: type JustifyContentProperty = 'center' | 'flex-start' | string & {}. With this change, any string is still assignable ...
Read more >
TypeScript Programming with Visual Studio Code
Get the best out editing TypeScript with Visual Studio Code. ... It offers classes, modules, and interfaces to help you build robust components....
Read more >
TypeScript | WebStorm Documentation - JetBrains
Auto import with suggestion from the TypeScript Language Service: no choices ... https://resources.jetbrains.com/help/img/idea/.
Read more >
Dynamic Suggestion Inputs with React Native, Typescript and ...
In order to get the null context to work with typescript I found the following helper function useful. export const AutoCompleteContext = ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found