jsonapi-serializer
jsonapi-serializer copied to clipboard
Typescript types?
Two questions:
-
Has anyone started writing types for the newer version of this package? Maybe we can share in this doc and/or get something up on DefinitelyTyped. I know there is ts-jsonapi but it's not being heavily used, maintained, nor is it up to date with this package.
-
Do the maintainers have any interest in adding types directly to this package since the API isn't changing much? cc @SeyZ
I just made this recently, I will continue and add more features as I need them (or you are welcome to do it 👍 )
declare module 'jsonapi-serializer' {
interface ISerializerOptions {
id?: string
attributes: string[]
pluralizeType?: boolean
typeForAttribute?: ITypeForAttribute
meta?: any
dataMeta?: any
}
interface ITypeForAttribute {
(attribute: string, object?: any)
}
interface IDeserializerOptions {
id?: string
keyForAttribute?: 'dash-case' | 'lisp-case' | 'spinal-case' | 'kebab-case' | 'underscore_case' | 'snake_case' | 'camelCase' | 'CamelCase'
}
interface IDeserializerConstructor {
new(opts: IDeserializerOptions): IDeserializer
}
interface ISerializerConstructor {
new(collectionName: string, opts: ISerializerOptions): ISerializer
}
interface IErrorConstructor {
new(opts: IJSONAPIErrorOptions): IJSONAPIError
}
interface IJSONAPIError {
errors: any[]
}
interface IJSONAPIErrorOptions {
id?: string
status?: string
code?: string
title?: string
detail?: string
source: {
pointer?: string
parameter?: string
}
links?: {
about?: string
}
meta?: any
}
interface ISerializer {
serialize(data: any): any
}
interface IDeserializer {
deserialize(data: any, callback: ICallback): void
deserialize(data: any): Promise<any>
}
interface ICallback {
(error: Error, response: any)
}
export let Serializer: ISerializerConstructor
export let Deserializer: IDeserializerConstructor
export let Error: IErrorConstructor
}
declare module 'jsonapi-serializer' {
type RefFunction = (current: any, item: any) => string;
export interface IRelation {
ref: string | RefFunction;
attributes?: string[];
included?: boolean;
}
interface ISerializerOptions {
id?: string;
attributes: string[];
pluralizeType?: boolean;
typeForAttribute?: ITypeForAttribute;
meta?: any;
dataMeta?: any;
}
interface ITypeForAttribute {
(attribute: string, object?: any): any;
}
interface ITransform {
(record: any): any;
}
interface IDeserializerOptions {
id?: string;
keyForAttribute?: 'dash-case' | 'lisp-case' | 'spinal-case' | 'kebab-case' | 'underscore_case' | 'snake_case' | 'camelCase' | 'CamelCase';
pluralizeType?: boolean;
typeAsAttribute?: boolean;
transform?: ITransform;
}
interface IDeserializerConstructor {
new(opts: IDeserializerOptions): IDeserializer;
}
interface ISerializerConstructor {
new(collectionName: string, opts: ISerializerOptions): ISerializer;
}
interface IErrorConstructor {
new(opts: IJSONAPIErrorOptions): IJSONAPIError;
}
interface IJSONAPIError {
errors: any[];
}
interface IJSONAPIErrorOptions {
id?: string;
status?: string;
code?: string;
title?: string;
detail?: string;
source: {
pointer?: string
parameter?: string,
};
links?: {
about?: string,
};
meta?: any;
}
interface ISerializer {
serialize(data: any): any;
}
interface IDeserializer {
deserialize(data: any, callback: ICallback): void;
deserialize(data: any): Promise<any>;
}
interface ICallback {
(error: Error, response: any): any;
}
// noinspection TsLint
export let Serializer: ISerializerConstructor;
// noinspection TsLint
export let Deserializer: IDeserializerConstructor;
// noinspection TsLint
export let Error: IErrorConstructor;
}
little bit extended variant
Maybe you could submit a PR to Definitely Typed ?
Made a few additions to ISerializerOptions above:
declare module 'jsonapi-serializer' {
type RefFunction = (current: any, item: any) => string;
export interface IRelation {
ref: string | RefFunction;
attributes?: string[];
included?: boolean;
}
interface ISerializerOptions {
ref?: Function | boolean | string;
included?: boolean;
id?: string;
attributes?: string[];
topLevelLinks?: string[] | Function[];
dataLinks?: string[] | Function[];
dataMeta?: Function | object;
relationshipLinks?: object;
relationshipMeta?: object;
ignoreRelationshipData?: boolean;
keyForAttribute?: string | IKeyForAttribute;
nullIfMissing?: boolean;
pluralizeType?: boolean;
typeForAttribute?: ITypeForAttribute;
meta?: object;
transform?: Function;
}
interface IKeyForAttribute {
(attribute: string): string;
}
interface ITypeForAttribute {
(attribute: string, object?: any): any;
}
interface ITransform {
(record: any): any;
}
interface IDeserializerOptions {
id?: string;
keyForAttribute?:
| 'dash-case'
| 'lisp-case'
| 'spinal-case'
| 'kebab-case'
| 'underscore_case'
| 'snake_case'
| 'camelCase'
| 'CamelCase';
pluralizeType?: boolean;
typeAsAttribute?: boolean;
transform?: ITransform;
}
interface IDeserializerConstructor {
new (opts: IDeserializerOptions): IDeserializer;
}
interface ISerializerConstructor {
new (collectionName: string, opts: ISerializerOptions): ISerializer;
}
interface IErrorConstructor {
new (opts: IJSONAPIErrorOptions): IJSONAPIError;
}
interface IJSONAPIError {
errors: any[];
}
interface IJSONAPIErrorOptions {
id?: string;
status?: string;
code?: string;
title?: string;
detail?: string;
source: {
pointer?: string;
parameter?: string;
};
links?: {
about?: string;
};
meta?: any;
}
interface ISerializer {
serialize(data: any): any;
}
interface IDeserializer {
deserialize(data: any, callback: ICallback): void;
deserialize(data: any): Promise<any>;
}
interface ICallback {
(error: Error, response: any): any;
}
// noinspection TsLint
export let Serializer: ISerializerConstructor;
// noinspection TsLint
export let Deserializer: IDeserializerConstructor;
// noinspection TsLint
export let Error: IErrorConstructor;
}
If I find time, I'll try to submit a PR to DT.
@chiangf what is the status of this?
@johannesschobel just pushed a PR into dt
Thanks
We should be able to resolve this issue now that https://github.com/DefinitelyTyped/DefinitelyTyped/pull/32057 has been merged 👍
Dear @chiangf ,
i have a question regarding your typings.. I was trying to add relationships to a serializer, however, i did not manage to solve this issue. Here is my code so far:
const serializer = new Serializer('users', {
attributes: ['username', 'email', 'createdAt', 'updatedAt', 'projects'],
keyForAttribute: 'camelCase',
projects: {
ref: 'id',
included: true,
attributes: ['name', 'description'],
}
});
The IDE indicates the projects
with the red squiggly lines, saing that there is no property projects
in the SerializerOptions
.
Unfortunately, i was not able to add an [prop: string]?: Relation
property to the SerializerOptions
to "fix" this.. How do you manage to add relations?
All the best
I am using "@types/jsonapi-serializer": "^3.6.2", shouldn't the default opts
constructor parameter be nullable for Deserializer?
By example in the README I see that it is optional.
@johannesschobel, I've added [key: string]: Relation | any;
locally, to avoid these errors. Not the best solution, so if someone will be able to provide a better one that would be great! If not, I will send a PR later.
export interface SerializerOptions {
ref?: (() => void) | boolean | string;
included?: boolean;
id?: string;
attributes?: string[];
topLevelLinks?: string[] | Array<() => void>;
dataLinks?: string[] | Array<() => void>;
dataMeta?: (() => void) | object;
relationshipLinks?: object;
relationshipMeta?: object;
ignoreRelationshipData?: boolean;
keyForAttribute?: string | KeyForAttribute;
nullIfMissing?: boolean;
pluralizeType?: boolean;
typeForAttribute?: TypeForAttribute;
meta?: object;
transform?: (() => void);
}
Is it correct that the dataLinks
property is an array?
We're also missing something like:
export interface SerializerOptions {
[key: string]: {
valueForRelationship: (relationship) => any
transform: (obj: any) => any
};
}
The way this function is written in JS makes it really hard to make a TS definition that's able to infer the types.
https://github.com/basarat/typescript-book/blob/master/docs/types/index-signatures.md#excluding-certain-properties-from-the-index-signature Meaning if we update the definition to
type DeserializerExtras<T extends string> = {
[key in T]: {
valueForRelationship: (relationship: any) => { id: string };
transform: (o: any) => any;
}
}
export interface DeserializerConstructor {
new<T extends string>(opts: DeserializerOptions & DeserializerExtras<T>): Deserializer;
}
We have to explicitly write down the properties not part of DeserializerOptions
that we would like to use:
JSONAPIDeserializer.Deserialize<'address' | 'origin'>({
keyForAttribute: "camelCase",
address: (addressRel) => addressRel.id;
origin: (originRel) => originRel.id;
}
If we don't do that, the code will complain that keyForAttribute
doesn't match our DeserializerExtras
signature.
some update about relationship?
@jairmedeiros topic was open in 2017, still no luck to this day ; it's fair to say @SeyZ is probably busy with something else or has let go of this lib.