Typescript: How to export data model typing to the Feathers client
Comment/Problem
Thanks to Feathers with Typescript, I can describe the data related to my service with ease:
// src/services/billing-departments/billing-departments.class.ts
import { Service, NedbServiceOptions } from 'feathers-nedb';
import { Application } from '../../declarations';
export interface BillingDepartmentsData {
code: string;
saleCommission: number;
basePrice: number;
}
export class BillingDepartments extends Service<BillingDepartmentsData> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
constructor(options: Partial<NedbServiceOptions>, app: Application) {
super(options);
}
}
export default null;
And I have the type checking enabled on my service calls:
app.service('billing-department').create({
// Got autocomplete en typecheck, yay!
});
However, this is not the case on my React Native typescript app with the feathers client:
import feathers from '@feathersjs/feathers';
import socketio from '@feathersjs/socketio-client';
import auth from '@feathersjs/authentication-client';
import { FeathersError } from '@feathersjs/errors';
const socket = io(Constants.manifest.extra.apiEndpoint, {
transports: ['websocket'],
});
const client = feathers();
client.configure(socketio(socket));
client.configure(auth({
storage: AsyncStorage,
}));
app.service('billing-department').create({
// Nothing is checked here.
});
And this is normal because the typing are... on the API project! :upside_down_face:
I found that I can specify a typing on the application: https://github.com/feathersjs/feathers/blob/cf2576b0ecd9a7195cfc4936420cddaeb413cced/packages/feathers/src/declarations.ts#L64
So I assume something like this:
import { MyServiceTyping } from '@my/api';
const client = feathers<MyServicesTyping>()
However, I don't really know what I have to export exactly from the API and how to do so.
A guide about that would be very welcomed. Having type checking on my front integrations would be a real plus for code reliability. :+1:
I found this generated declarations.d.ts file:
// src/declarations.d.ts
import { Application as ExpressFeathers } from '@feathersjs/express';
import '@feathersjs/transport-commons';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ServiceTypes {}
export type Application = ExpressFeathers<ServiceTypes>;
I assume I have to play with ServiceTypes. However, each generated service overrides this declaration file like this:
declare module '../../declarations' {
interface ServiceTypes {
'billing-departments': BillingDepartments & ServiceAddons<any>;
}
}
So I don't really know what to build and ship to my npm registry.
I did some test on the client side code and ended up with this:
// client.ts
import feathers, { Params, ServiceAddons } from '@feathersjs/feathers';
import { AdapterService } from '@feathersjs/adapter-commons';
export interface Service1Data {
// Some fields
};
export interface Service2Data {
// Some fields
};
type Service<T> = AdapterService<T> & ServiceAddons<T>;
interface ServiceTypes {
'service-1': Service<Service1Data>;
'service-2': Service<Service2Data>;
};
const client = feathers<ServiceTypes>();
client.service('service-1').create({
// Got autocompletion and type check.
});
This is working so know I now I have to export the ServicesTypes.
However, the server BillingDepartments class of my previous example is a feathers-nedb service:
// src/services/billing-departments/billing-departments.class.ts
import { Service, NedbServiceOptions } from 'feathers-nedb';
import { Application } from '../../declarations';
export interface BillingDepartmentsData {
// fields
}
export class BillingDepartments extends Service<BillingDepartmentsData> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
constructor(options: Partial<NedbServiceOptions>, app: Application) {
super(options);
}
}
export default null;
As it is useless to add feathers-nedb to my front dependency (the client is just a REST client as then end), how can I export a common ServicesTypes without duplicate my code with the current api declarations (nedb-service)?
If you want to share it you can remove the individual module overrides and put them all into a centra declarationl file. The reason why it doesn't do that is because it's extremely difficult to write a generator Codemod that can do this reliably.
@daffl Can you share a sample of it?
The v5 CLI now automatically generates a typed client from the data model that will be always up to date. You can try it out here.