Geocodio / geocodio-library-node

geocod.io Node library
MIT License
15 stars 6 forks source link

Adding Typescript Declarations #17

Open defensadev opened 3 years ago

defensadev commented 3 years ago

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 commented 2 years ago
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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 1 year ago

Extended from @Sparticuz

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 commented 6 months ago

@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!