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 support for @analytics/google-tag-manager #99

Open
hongbo-miao opened this issue Oct 3, 2020 · 13 comments
Open

TypeScript support for @analytics/google-tag-manager #99

hongbo-miao opened this issue Oct 3, 2020 · 13 comments

Comments

@hongbo-miao
Copy link

I am using @analytics/google-tag-manager.
I saw analytics have TypeScript support while @analytics/google-tag-manager not.

When add

import googleTagManager from '@analytics/google-tag-manager';

got

TS7016: Could not find a declaration file for module '@analytics/google-tag-manager'. '/hongbomiao.com/client/node_modules/@analytics/google-tag-manager/lib/analytics-plugin-google-tag-manager.cjs.js' implicitly has an 'any' type.   Try npm install @types/analytics__google-tag-manager if it exists or add a new declaration (.d.ts) file containing declare module '@analytics/google-tag-manager';

It would be great to add TypeScript in future. Thanks! : )

@DavidWells
Copy link
Owner

I would like to improve TS support for browser & node packages.

Running into some issues where the node/browser types are different but TS only allows for one type definition & doesn't follow the module resolution to grab the proper types.

From what I can tell, this might require publishing 2 separate packages. 1 for browser and 1 for serverside node... This is a bummer because it will double the amount of maintenance/packages for the project 😅

The solution proposed looks like a lot of work...

Will need to think on this one

@GeoMarkou
Copy link

As a workaround I added this code in a Types.ts file

declare module '@analytics/google-analytics' {
    type GoogleAnalyticsOptions = {
        /** Google Analytics site tracking Id */
        trackingId:string;

        /** Enable Google Analytics debug mode */
        debug?:boolean;

        /** Enable Anonymizing IP addresses sent to Google Analytics. See details below */
        anonymizeIp?:boolean;

        /** Map Custom dimensions to send extra information to Google Analytics. See details below */
        customDimensions?:object;

        /** Reset custom dimensions by key on analytics.page() calls. Useful for single page apps. */
        resetCustomDimensionsOnPage?:object;

        /** Mapped dimensions will be set to the page & sent as properties of all subsequent events on that page. If false, analytics will only pass custom dimensions as part of individual events */
        setCustomDimensionsToPage?:boolean;

        /** Custom tracker name for google analytics. Use this if you need multiple googleAnalytics scripts loaded */
        instanceName?:string;

        /** Custom URL for google analytics script, if proxying calls */
        customScriptSrc?:string;

        /** Additional cookie properties for configuring the ga cookie */
        cookieConfig?:object;

        /** Set custom google analytic tasks */
        tasks?:object;
    };
    
    type AnalyticsPlugin = {
        /** Name of plugin */
        name: string;

        /** exposed events of plugin */
        EVENTS?: any;

        /** Configuration of plugin */
        config?: any;

        /** Load analytics scripts method */
        initialize?: (...params: any[]) => any;

        /** Page visit tracking method */
        page?: (...params: any[]) => any;

        /** Custom event tracking method */
        track?: (...params: any[]) => any;

        /** User identify method */
        identify?: (...params: any[]) => any;

        /** Function to determine if analytics script loaded */
        loaded?: (...params: any[]) => any;

        /** Fire function when plugin ready */
        ready?: (...params: any[]) => any;
    };

    function GoogleAnalytics (options:GoogleAnalyticsOptions):AnalyticsPlugin;
    export default GoogleAnalytics;
}

@saiichihashimoto
Copy link

What can we do to help @DavidWells? It's unclear what the solution is here since it looks like the typescript files in this repo are generated.

@DavidWells
Copy link
Owner

I'm stuck on the issue where types can be different between server and client implementations

https://twitter.com/DavidWells/status/1340059740672442368

It seems like this isn't supported in typescript and this is a real bummer

@GeoMarkou
Copy link

GeoMarkou commented Jan 14, 2021

Just some ideas: the way I've seen other libraries do it is to have a separate folders. If the code is completely different between the 2 this makes a lot of sense - then the programmer just imports the one that they want. e.g.

import Analytics from '@analytics/google-analytics/browser';
// or
import Analytics from '@analytics/google-analytics/node';

I've also seen libraries have a single class but they want to restrict some functions*. So you would have a single class, but export it twice with different types so that the programmer can choose what makes sense for them. e.g.

/** This is stuff that is shared to both node.js and browser */
type CommonModules = {
    GenericFunc: () => void;
}

/** Browser specific definitions */
type BrowserModules = CommonModules & {
    BrowserFunc: () => void;
}

/** Server specific definitions */
type ServerModules = CommonModules & {
    ServerFunc: () => void;
}

/** Write all your code */
const AllMyCode:BrowserModules&ServerModules = {
    GenericFunc: () => {},
    BrowserFunc: () => {},
    ServerFunc: () => {}
};

/** Restricted set of browser functions */
const BrowserCode = AllMyCode as BrowserModules;
export BrowserCode;

/** Restricted set of server functions */
const ServerCode = AllMyCode as ServerModules;
export ServerCode;

// Inside user code, they import which one they want
import { BrowserCode, ServerCode } from '@analytics/google-analytics';

Dunno if this helps or not

@saiichihashimoto
Copy link

So you would have a single class, but export it twice with different types so that the programmer can choose what makes sense for them. e.g.

Since you're not using typescript internally, there's something to be said here; you're NOT using typescript internally so it's ultimately about exporting types so users can use it. You could export a Browser Type, Node Type, and union type and have your functions use the union types. Being less strict is not ideal, but then you're allowing us to cast to the more specific types when we need to, which solves our issue much more than having no type at all.

@xoscar
Copy link

xoscar commented Apr 25, 2022

bump

@livthomas
Copy link

The original question was about @analytics/google-tag-manager. And although @GeoMarkou posted a really good workaround for @analytics/google-analytics, those types are a little bit different.

Here are the types for @analytics/google-tag-manager package:

declare module '@analytics/google-tag-manager' {
  type AnalyticsPlugin = import('analytics').AnalyticsPlugin;

  type GoogleTagManagerConfig = {
    auth?: string;
    containerId: string;
    customScriptSrc?: string;
    dataLayerName?: string;
    debug?: boolean;
    execution?: string;
    preview?: string;
  };

  function googleTagManager(config: GoogleTagManagerConfig): AnalyticsPlugin;
  export default googleTagManager;
}

@santyas
Copy link

santyas commented Jul 25, 2022

The original question was about @analytics/google-tag-manager. And although @GeoMarkou posted a really good workaround for @analytics/google-analytics, those types are a little bit different.

Here are the types for @analytics/google-tag-manager package:

declare module '@analytics/google-tag-manager' {
  type AnalyticsPlugin = import('analytics').AnalyticsPlugin;

  type GoogleTagManagerConfig = {
    auth?: string;
    containerId: string;
    customScriptSrc?: string;
    dataLayerName?: string;
    debug?: boolean;
    execution?: string;
    preview?: string;
  };

  function googleTagManager(config: GoogleTagManagerConfig): AnalyticsPlugin;
  export default googleTagManager;
}

where do you insert that code? or GeoMarkou declare?

@livthomas
Copy link

@santyas You simply put it to something.d.ts file anywhere in your project and TypeScript will pick it up.

@nifalconi
Copy link

nifalconi commented Apr 12, 2024

For the GA4, the declared module should be:

declare module '@analytics/google-analytics' {
  type GoogleAnalyticsOptions = {
      /** Google Analytics MEASUREMENT IDs */
      measurementIds: string[];

      /** Enable Google Analytics debug mode */
      debug?: boolean;

      /** The optional name for dataLayer object. Defaults to 'ga4DataLayer'. */
      dataLayerName?: string;

      /** The optional name for the global gtag function. Defaults to 'gtag'. */
      gtagName?: string;

      /** Configuration for gtag, including anonymizing IP and cookie settings */
      gtagConfig?: {
          anonymize_ip?: boolean;
          cookie_domain?: string;
          cookie_expires?: number;
          cookie_prefix?: string;
          cookie_update?: boolean;
          cookie_flags?: string;
      };

      /** Custom URL for google analytics script, if proxying calls */
      customScriptSrc?: string;
  };

  type AnalyticsPlugin = {
      /** Name of plugin */
      name: string;

      /** Exposed events of the plugin */
      EVENTS?: any;

      /** Configuration of the plugin */
      config?: any;

      /** Method to load analytics scripts */
      initialize?: (...params: any[]) => any;

      /** Page visit tracking method */
      page?: (...params: any[]) => any;

      /** Custom event tracking method */
      track?: (...params: any[]) => any;

      /** User identify method */
      identify?: (...params: any[]) => any;

      /** Function to determine if analytics script is loaded */
      loaded?: (...params: any[]) => any;

      /** Fire function when the plugin is ready */
      ready?: (...params: any[]) => any;
  };

  function GoogleAnalytics(options: GoogleAnalyticsOptions): AnalyticsPlugin;
  export default GoogleAnalytics;
}

This should be added on something.d.ts like @livthomas pointed out.

@aprilmintacpineda
Copy link

Unfortunately we still don't have this until today :(

@fromaline
Copy link

+1

I just ran into the same issue. Adding types for @analytics/google-analytics would be extremely helpful — TypeScript is everywhere!

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

10 participants