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

Adding Typescript Declarations #17

Open
defensadev opened this issue Jun 21, 2021 · 6 comments
Open

Adding Typescript Declarations #17

defensadev opened this issue Jun 21, 2021 · 6 comments

Comments

@defensadev
Copy link

Hello, I really love geocodio, it's a great service and the node library work well.

I found it was missing a @types/geocodio-library-node module. So I made some quick type declarations for my work as I had to build it around a pre existing project.

I just wanted to leave it here for improvement and to help anybody out. It might not be exact and have some errors, I put it together rather quickly by just looking at the docs and testing the responses.

type GeocodeProps = string | Array<string>;

interface GeocodedAddress {
  address_components: {
    number?: string;
    predirectional?: string;
    street?: string;
    suffix?: string;
    formatted_street?: string;
    secondaryunit?: string;
    secondarynumber?: string;
    city: string;
    county?: string;
    state: string;
    zip: string;
    country?: string;
  };
  formatted_address: string;
  location: { lat: number; lng: number };
  accuracy?: number;
  accuracy_type?: string;
  source?: string;
}

interface GeocodedResponse {
  results: [GeocodedAddress];
}

interface GeocodedArrayResponse {
  results: Array<{
    query: string;
    response: {
      input: any;
      results: [GeocodedAddress];
    };
  }>;
}

declare module "geocodio-library-node" {
  export default class Geocodio {
    constructor(apiKey: string);

    geocode(
      x: GeocodeProps,
      y: Array<any>,
      z: number
    ): GeocodeProps extends string
      ? Promise<GeocodedResponse>
      : Promise<GeocodedArrayResponse>;
  }
}
@Theauxm
Copy link

Theauxm commented Feb 22, 2022

declare module "geocodio-library-node" {
  export interface AddressParts {
    country?: string;
    street?: string;
    city?: string;
    state?: string;
    postal_code?: string;
  }

  export type AddressMap = {
    [key: string]: string;
  };

  export type AddressComponents = {
    number?: string;
    predirectional?: string;
    street?: string;
    suffix?: string;
    formatted_street?: string;
    secondaryunit?: string;
    secondarynumber?: string;
    city: string;
    county?: string;
    state: string;
    zip: string;
    country?: string;
  };

  export interface GeocodedAddress {
    address_components: AddressComponents;
    formatted_address: string;
    location: { lat: number; lng: number };
    accuracy?: number;
    accuracy_type?: string;
    source?: string;
    fields?: { [key: string]: string };
  }

  export interface GeocodedResponse {
    input: {
      address_components: AddressComponents;
      formatted_address: string;
    };
    results: [GeocodedAddress];
  }

  export interface GeocodedArrayResponse {
    results: Array<{
      query: string;
      response: GeocodedResponse;
      results: [GeocodedAddress];
    }>;
  }

  export type AddressParam =
    | string
    | string[]
    | AddressParts
    | AddressParts[]
    | AddressMap;

  export type CoordinatesParam = string | string[] | [number, number];

  export default class Geocodio {
    constructor(apiKey?: string);

    geocode(
      address: AddressParam,
      options?: string[],
      limit?: number
    ): Promise<GeocodedResponse | GeocodedArrayResponse>;

    reverse(
      coordinates: CoordinatesParam,
      options?: string[],
      limit?: number
    ): Promise<GeocodedResponse | GeocodedArrayResponse>;
  }
}

@defensadev
Copy link
Author

Brilliant! Haven't worked on this in a while, I just use my type defs as they satisfy what I'm working on. Good to see there's a complete list here. I'll put them in my .d.ts right now.

@Theauxm
Copy link

Theauxm commented Feb 23, 2022

I reworked it slightly as I couldn't figure out how to get a Simple response to be returned from the library. Apologies about the non-usage of ternary types, couldn't figure that one out!

@Sparticuz
Copy link

I've added error and _warnings to @Theauxm's types. Also my linter wants things alphabetized, so I did that too

declare module "geocodio-library-node" {
  export interface AddressParts {
    city?: string;
    country?: string;
    postal_code?: string;
    state?: string;
    street?: string;
  }

  export type AddressMap = {
    [key: string]: string;
  };

  export type AddressComponents = {
    city: string;
    country?: string;
    county?: string;
    formatted_street?: string;
    number?: string;
    predirectional?: string;
    secondarynumber?: string;
    secondaryunit?: string;
    state: string;
    street?: string;
    suffix?: string;
    zip: string;
  };

  export interface GeocodedAddress {
    _warnings?: string[];
    accuracy?: number;
    accuracy_type?: string;
    address_components: AddressComponents;
    fields?: { [key: string]: string };
    formatted_address: string;
    location: { lat: number; lng: number };
    source?: string;
  }

  export interface GeocodedResponse {
    _warnings?: string[];
    input: {
      address_components: AddressComponents;
      formatted_address: string;
    };
    results: [GeocodedAddress];
  }

  export interface GeocodedArrayResponse {
    results: Array<{
      query: string;
      response: GeocodedResponse;
      results: [GeocodedAddress];
    }>;
  }

  export interface GeocodedErrorResponse {
    error: string;
  }

  export type AddressParam =
    | string
    | string[]
    | AddressParts
    | AddressParts[]
    | AddressMap;

  export type CoordinatesParam = string | string[] | [number, number];

  export default class Geocodio {
    constructor(apiKey?: string);

    geocode(
      address: AddressParam,
      options?: string[],
      limit?: number
    ): Promise<
      GeocodedResponse | GeocodedArrayResponse | GeocodedErrorResponse
    >;

    reverse(
      coordinates: CoordinatesParam,
      options?: string[],
      limit?: number
    ): Promise<
      GeocodedResponse | GeocodedArrayResponse | GeocodedErrorResponse
    >;
  }
}

And some type guards

function isGeocodedError(
  response: GeocodedArrayResponse | GeocodedResponse | GeocodedErrorResponse
): response is GeocodedErrorResponse {
  return (response as GeocodedErrorResponse).error !== undefined;
}

function isGeocodedArrayResponse(
  response: GeocodedArrayResponse | GeocodedResponse | GeocodedErrorResponse
): response is GeocodedArrayResponse {
  return (response as GeocodedArrayResponse).results[0].query !== undefined;
}

@TheSecurityDev
Copy link

TheSecurityDev commented Aug 5, 2023

Extended from @Sparticuz

  • Changed [GeocodedAddress] to GeocodedAddress[] because it can contain more than one result.
  • Added GeocodeAccuracyType, with different values for Forward or Reverse lookups
  • Added InputAddressComponents, since the secondaryunit and secondarynumber fields are only available on the input address.
declare module "geocodio-library-node" {
  export interface AddressParts {
    city?: string;
    country?: string;
    postal_code?: string;
    state?: string;
    street?: string;
  }

  export type AddressMap = {
    [key: string]: string;
  };

  export interface AddressComponents {
    city: string;
    country?: string;
    county?: string;
    formatted_street?: string;
    number?: string;
    predirectional?: string;
    state: string;
    street?: string;
    suffix?: string;
    zip: string;
  }

  export interface InputAddressComponents extends AddressComponents {
    secondarynumber?: string;
    secondaryunit?: string;
  }

  export type ForwardGeocodeAccuracyType =
    | "rooftop"
    | "point"
    | "range_interpolation"
    | "nearest_rooftop_match"
    | "intersection"
    | "street_center"
    | "place"
    | "county"
    | "state";

  export type ReverseGeocodeAccuracyType = "rooftop" | "nearest_street" | "nearest_place";

  export type GeocodeAccuracyType = ForwardGeocodeAccuracyType | ReverseGeocodeAccuracyType;

  export interface GeocodedAddress<T = GeocodeAccuracyType> {
    _warnings?: string[];
    accuracy?: number;
    accuracy_type?: T;
    address_components: AddressComponents;
    fields?: { [key: string]: string };
    formatted_address: string;
    location: { lat: number; lng: number };
    source?: string;
  }

  export interface GeocodedResponse<T = GeocodeAccuracyType> {
    _warnings?: string[];
    input: {
      address_components: InputAddressComponents;
      formatted_address: string;
    };
    results: GeocodedAddress<T>[];
  }

  export interface GeocodedArrayResponse<T = GeocodeAccuracyType> {
    results: Array<{
      query: string;
      response: GeocodedResponse<T>;
      results: GeocodedAddress<T>[];
    }>;
  }

  export interface GeocodedErrorResponse {
    error: string;
  }

  export type AddressParam = string | string[] | AddressParts | AddressParts[] | AddressMap;

  export type CoordinatesParam = string | string[] | [number, number];

  export default class Geocodio {
    constructor(apiKey?: string);

    geocode(
      address: AddressParam,
      options?: string[],
      limit?: number
    ): Promise<
      | GeocodedResponse<ForwardGeocodeAccuracyType>
      | GeocodedArrayResponse<ForwardGeocodeAccuracyType>
      | GeocodedErrorResponse
    >;

    reverse(
      coordinates: CoordinatesParam,
      options?: string[],
      limit?: number
    ): Promise<
      | GeocodedResponse<ReverseGeocodeAccuracyType>
      | GeocodedArrayResponse<ReverseGeocodeAccuracyType>
      | GeocodedErrorResponse
    >;
  }
}

@MiniCodeMonkey
Copy link
Member

@Sparticuz @Theauxm @TheSecurityDev @defensadev Thanks for your collaboration on putting together the Typescript declarations. We would be happy to accept a PR to add these to the library if you'd like. Thanks!

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

No branches or pull requests

5 participants