Skip to content

Commit

Permalink
fix: posthog init should reject invalid config in TypeScript (#1097)
Browse files Browse the repository at this point in the history
We've seen the reasonable typo of Id for ID when people use distinct id bootstrapping with this SDK

see https://twitter.com/illyism/status/1771586772067123490

Because we accept Partial<PostHogConfig> into init Typescript doesn't check for additional keys

With some typescript magic we can change that behavior without breaking the ability to only pass partial config
  • Loading branch information
pauldambra authored Mar 23, 2024
1 parent d6280fb commit 3f6f550
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 7 deletions.
16 changes: 15 additions & 1 deletion src/posthog-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ this.__x === private - only use within the class
Globals should be all caps
*/

/* posthog.init is called with `Partial<PostHogConfig>`
* and we want to ensure that only valid keys are passed to the config object.
* TypeScript does not enforce that the object passed does not have extra keys.
* So someone can call with { bootstrap: { distinctId: '123'} }
* which is not a valid key. They should have passed distinctID (upper case D).
* That's a really tricky mistake to spot.
* The OnlyValidKeys type ensures that only keys that are valid in the PostHogConfig type are allowed.
*/
type OnlyValidKeys<T, Shape> = T extends Shape ? (Exclude<keyof T, keyof Shape> extends never ? T : never) : never

const instances: Record<string, PostHog> = {}

// some globals for comparisons
Expand Down Expand Up @@ -271,7 +281,11 @@ export class PostHog {
* @param {Object} [config] A dictionary of config options to override. <a href="https://github.com/posthog/posthog-js/blob/6e0e873/src/posthog-core.js#L57-L91">See a list of default config options</a>.
* @param {String} [name] The name for the new posthog instance that you want created
*/
init(token: string, config?: Partial<PostHogConfig>, name?: string): PostHog | void {
init(
token: string,
config?: OnlyValidKeys<Partial<PostHogConfig>, Partial<PostHogConfig>>,
name?: string
): PostHog | void {
if (!name || name === PRIMARY_INSTANCE_NAME) {
// This means we are initializing the primary instance (i.e. this)
return this._init(token, config, name)
Expand Down
14 changes: 8 additions & 6 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ export interface AutocaptureConfig {
capture_copied_text?: boolean
}

export interface BootstrapConfig {
distinctID?: string
isIdentifiedID?: boolean
featureFlags?: Record<string, boolean | string>
featureFlagPayloads?: Record<string, JsonType>
}

export interface PostHogConfig {
api_host: string
/** @deprecated - This property is no longer supported */
Expand Down Expand Up @@ -132,12 +139,7 @@ export interface PostHogConfig {
capture_performance?: boolean
// Should only be used for testing. Could negatively impact performance.
disable_compression: boolean
bootstrap: {
distinctID?: string
isIdentifiedID?: boolean
featureFlags?: Record<string, boolean | string>
featureFlagPayloads?: Record<string, JsonType>
}
bootstrap: BootstrapConfig
segment?: any
__preview_send_client_session_params?: boolean
disable_scroll_properties?: boolean
Expand Down

0 comments on commit 3f6f550

Please sign in to comment.