Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript Definitions #60

Open
johannesschobel opened this issue Jan 9, 2019 · 11 comments
Open

TypeScript Definitions #60

johannesschobel opened this issue Jan 9, 2019 · 11 comments

Comments

@johannesschobel
Copy link

Hey there,
i am currently evaluating this package to be used in a TypeScript REST API. So i was wondering, if there are some TypeScript Definitions available?!

All the best

@danivek
Copy link
Owner

danivek commented Mar 6, 2019

I have no plan to work on this topic at the moment but feel free to open a PR.

@johannesschobel
Copy link
Author

thanks for pointing this out..

@pupudu
Copy link

pupudu commented Feb 11, 2020

@danivek @johannesschobel
Would you consider keeping this issue open until TS definitions are added to this library (or the whole library converted to use TS)?
Personally, I think keeping this issue open and inviting people to contribute to that aspect will be a good thing for the future of this library.

Anyway, many thanks for creating this amazing library. This is the best json-api compliant library I could find after weeks of research. 🙏

@johannesschobel
Copy link
Author

I mean.. I can reopen it if you both like, what do you think @danivek ?

@danivek
Copy link
Owner

danivek commented Feb 11, 2020

@pupudu Thanks!

Keeping this issue open is fine for me!

I started to work a bit on adding TS definitions, but I don't have a lot of experience on TS and it seems a bit verbose for me.

Here is my starting point.

declare class JSONAPISerializer {
    constructor(options?: JSONAPISerializer.Options);

    register(type: string, schema?: string | JSONAPISerializer.Options, options?: JSONAPISerializer.Options): void;

    serialize(type: string | object, data: any, schema?: string, extraData?: any, excludeData?: boolean, overrideSchemaOptions?: JSONAPISerializer.Options): void;
    
    serializeAsync(type: string | object, data: any, schema?: string, extraData?: any, excludeData?: boolean, overrideSchemaOptions?: JSONAPISerializer.Options): Promise<any>;

    deserialize(type: string, data: any, schema?: string): void;

    deserializeAsync(type: string, data: any, schema?: string): Promise<any>;

    serializeError(error: any): void;
}

declare namespace JSONAPISerializer {

    export type Options = {
        id?: string,
        blacklist?: string[],
        whitelist?: string[],
        jsonapiObject?: boolean,
        links?: (() => void) | object,
        relationships?: object,
        topLevelLinks?: (() => void) | object,
        topLevelMeta?: (() => void) | object,
        meta?: (() => void) | object,
        blacklistOnDeserialize?: string[],
        whitelistOnDeserialize?: string[],
        convertCase?: string,
        unconvertCase?: string,
        convertCaseCacheSize?: number
    }
}

export = JSONAPISerializer;

If someone could guide me on this it would be great!

@pupudu
Copy link

pupudu commented Feb 14, 2020

@danivek Looks good to me. Another possibility would be to migrate the source code itself to TS so that it won't look unnecessarily verbose, and will prevent inconsistencies in types and source code.

Thanks for adding the help-wanted & good-first-issue flags to the issue. 🙏
I will try to get some time from my team to make this possible.

@danivek
Copy link
Owner

danivek commented May 26, 2020

Update

interface RelationshipOptions {
    type: string;
    alternativeKey?: string;
    schema?: string;
    links?: ((data: object, extraData: object) => object) | object;
    meta?: ((data: object, extraData: object) => object) | object;
    deserialize?: ((data: object) => object);
}

interface Options {
    id?: string;
    blacklist?: string[];
    whitelist?: string[];
    jsonapiObject?: boolean;
    links?: ((data: object, extraData: object) => object) | object;
    topLevelLinks?: ((data: object, extraData: object) => object) | object;
    topLevelMeta?: ((data: object, extraData: object) => object) | object;
    meta?: ((data: object, extraData: object) => object) | object;
    relationships?: {
        [x: string]: RelationshipOptions;
    };
    blacklistOnDeserialize?: string[];
    whitelistOnDeserialize?: string[];
    convertCase?: ('kebab-case' | 'snake_case' | 'camelCase');
    unconvertCase?: ('kebab-case' | 'snake_case' | 'camelCase');
    convertCaseCacheSize?: number;
    beforeSerialize?: ((data: object) => object);
    afterDeserialize?: ((data: object) => object);
}

interface DynamicTypeOptions {
    id: (data: object) => object | string;
    jsonapiObject?: boolean;
    topLevelLinks?: ((data: object, extraData: object) => object) | object;
    topLevelMeta?: ((data: object, extraData: object) => object) | object;
}

type ErrorWithStatus = Error;

declare namespace JSONAPISerializer {
    export { RelationshipOptions, Options, ErrorWithStatus, DynamicTypeOptions };
}

declare class JSONAPISerializer {
    constructor(opts?: Options);
    register(type: string, options?: Options): void;
    register(type: string, schema?: string, options?: Options): void;
    serialize(type: string | DynamicTypeOptions, data: object | object[], schema?: string | object, extraData?: object, excludeData?: boolean, overrideSchemaOptions?: object): any;
    serializeAsync(type: string | DynamicTypeOptions, data: object | object[], schema?: string, extraData?: object, excludeData?: boolean, overrideSchemaOptions?: object): Promise<any>;
    deserialize(type: string | DynamicTypeOptions, data: object, schema?: string): any;
    deserializeAsync(type: string | DynamicTypeOptions, data: object, schema?: string): Promise<any>;
    serializeError(error: Error | Error[] | ErrorWithStatus | ErrorWithStatus[] | object | object[]): Promise<any>;
}

export = JSONAPISerializer;

If someone could test this it would be great!

@stefanvanherwijnen
Copy link
Contributor

I think data: object should be changed to data: { [key: string]: string }, otherwise TS complains about the keys not being defined in object.

@danivek
Copy link
Owner

danivek commented Jun 5, 2020

@stefanvanherwijnen Thank you for your feedback

Update:

interface RelationshipOptions {
    type: string;
    alternativeKey?: string;
    schema?: string;
    links?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string) };
    meta?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string) };
    deserialize?: ((data: { [key: string]: string }) => { [key: string]: string });
}

interface Options {
    id?: string;
    blacklist?: string[];
    whitelist?: string[];
    jsonapiObject?: boolean;
    links?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string)};
    topLevelLinks?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string)};
    topLevelMeta?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string)};
    meta?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string) };
    relationships?: {
        [x: string]: RelationshipOptions;
    };
    blacklistOnDeserialize?: string[];
    whitelistOnDeserialize?: string[];
    convertCase?: ('kebab-case' | 'snake_case' | 'camelCase');
    unconvertCase?: ('kebab-case' | 'snake_case' | 'camelCase');
    convertCaseCacheSize?: number;
    beforeSerialize?: ((data: { [key: string]: string }) => { [key: string]: string });
    afterDeserialize?: ((data: { [key: string]: string }) => { [key: string]: string });
}

interface DynamicTypeOptions {
    type: (data: { [key: string]: string }) => string;
    jsonapiObject?: boolean;
    topLevelLinks?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string) };
    topLevelMeta?: ((data: { [key: string]: string }, extraData: any) => { [key: string]: string }) | { [key: string]: string | ((data: { [key: string]: string }, extraData: any) => string) };
}

type ErrorWithStatus = Error;

declare namespace JSONAPISerializer {
    export { RelationshipOptions, Options, ErrorWithStatus, DynamicTypeOptions };
}

declare class JSONAPISerializer {
    constructor(opts?: Options);
    register(type: string, options?: Options): void;
    register(type: string, schema?: string, options?: Options): void;
    serialize(type: string | DynamicTypeOptions, data: any | any[], schema?: string | { [key: string]: string }, extraData?: any, excludeData?: boolean, overrideSchemaOptions?: { [key: string]: string }): any;
    serializeAsync(type: string | DynamicTypeOptions, data: any | any[], schema?: string, extraData?: any, excludeData?: boolean, overrideSchemaOptions?: { [key: string]: string }): Promise<any>;
    deserialize(type: string | DynamicTypeOptions, data: any, schema?: string): any;
    deserializeAsync(type: string | DynamicTypeOptions, data: any, schema?: string): Promise<any>;
    serializeError(error: Error | Error[] | ErrorWithStatus | ErrorWithStatus[] | { [key: string]: string } | { [key: string]: string }[]): Promise<any>;
}

export = JSONAPISerializer;

@Istanful
Copy link
Contributor

Istanful commented Apr 1, 2021

I've got a PR open in the DefinitelyTyped repository. Feel free to use those types directly in this project or as a workaround.

The PR: DefinitelyTyped/DefinitelyTyped#52110

The types:

// Type definitions for json-api-serializer 2.6 Project: https://github.com/danivek/json-api-serializer#readme
// Definitions by: Emric <https://github.com/Istanful>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped

declare module 'json-api-serializer' {
  namespace JSONAPISerializer {
    type TypeCallback = (
      relationshipData: { [key: string]: RelationshipOptions },
      data: unknown
    ) => unknown;

    type LinksCallback = (data: unknown, extraData?: unknown) => string | LinksObject;

    type MetaCallback = (data: unknown, extraData?: unknown) => unknown;

    type BeforeSerializeCallback = (data: unknown) => unknown;

    type AfterDeseralizeCallback = (data: unknown) => unknown;

    interface RelationshipOptions {
      type: string | TypeCallback;
      alternativeKey?: string;
      schema?: string;
      links?: LinksObject | LinksCallback;
      meta?: MetaCallback | unknown;
      beforeSerialize?: BeforeSerializeCallback;
    }

    type Case = 'kebab-case' | 'snake_case' | 'camelCase';

    interface Options {
      id?: string;
      blacklist?: string[];
      whitelist?: string[];
      jsonapiObject?: boolean;
      links?: LinksObject | LinksCallback;
      topLevelLinks?: LinksCallback | LinksObject;
      topLevelMeta?: MetaCallback | unknown;
      meta?: MetaCallback | unknown;
      relationships?: {
        [key: string]: RelationshipOptions;
      };
      blacklistOnDeserialize?: string[];
      whitelistOnDeserialize?: string[];
      convertCase?: Case;
      unconvertCase?: Case;
      convertCaseCacheSize?: number;
      beforeSerialize?: BeforeSerializeCallback;
      afterDeserialize?: AfterDeseralizeCallback;
    }

    interface DynamicTypeOptions {
      id?: string;
      jsonapiObject?: boolean;
      topLevelLinks?: LinksObject | LinksCallback;
      topLevelMeta?: unknown | MetaCallback;
    }

    interface LinkObject {
      href: string;
      meta: unknown;
    }

    interface LinksObject {
      [name: string]: LinkObject | LinksCallback | string | null;
    }

    interface ResourceObject<T> {
      id: string;
      type: string;
      attributes?: Omit<T, 'id'>;
      relationships?: {
        [key: string]: { data: ResourceObject<any> | Array<ResourceObject<any>> };
      };
      links?: LinksObject | LinksCallback;
    }

    interface JsonApiObject {
      version: string;
    }

    interface ErrorObject {
      id?: string;
      links?: LinksObject & {
        about: LinkObject | string;
      };
      status?: string;
      code?: string;
      title?: string;
      detail?: string;
      source?: unknown;
      meta?: unknown;
    }

    interface JSONAPIDocument {
      jsonapi?: JsonApiObject;
      links?: LinksObject;
      data?: ResourceObject<unknown> | Array<ResourceObject<unknown>>;
      errors?: ErrorObject[];
      meta?: { [key: string]: unknown };
      included?: Array<ResourceObject<unknown>>;
    }
  }

  class JSONAPISerializer {
    register(type: string, schema?: string | Options, opts?: Options): void;

    serialize(type: string, data: unknown, topLevelMeta?: unknown): JSONAPIDocument;

    serialize(
      type: string,
      data: unknown,
      schema?: string | Options,
      topLevelMeta?: unknown,
      excludeTopLevelMeta?: boolean,
      overrideSchemaOptions?: { [type: string]: Options }
    ): JSONAPIDocument;

    serializeAsync(
      type: string | DynamicTypeOptions,
      data: unknown | unknown[],
      schema?: string,
      topLevelMeta?: unknown,
      excludeTopLevelMeta?: boolean,
      overrideSchemaOptions?: { [type: string]: Options }
    ): Promise<JSONAPIDocument>;

    deserialize(type: string | DynamicTypeOptions, data: JSONAPIDocument, schema?: string): any;

    deserializeAsync(
      type: string | DynamicTypeOptions,
      data: JSONAPIDocument,
      schema?: string
    ): Promise<any>;

    serializeError(error: ErrorObject | ErrorObject[] | Error | Error[]): ErrorObject;
  }

  export = JSONAPISerializer;
}

@Istanful
Copy link
Contributor

Istanful commented Apr 3, 2021

The types are now available to install as a standalone package.

Install with yarn:

yarn add -D @types/json-api-serializer

Install with npm:

npm install --save-dev @types/json-api-serializer

@danivek Please let me know if you want me to open a PR to this repository with the types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants