Home > Software engineering >  TS Type guard doesn't detect a non-empty class object property
TS Type guard doesn't detect a non-empty class object property

Time:12-15

I have the following problem with TypeScript. There is a class property of the following type AmplitudeFeatureFlags | {} = {}; and equals an empty object by default. I have a method that receives a property name arg of enum type to retrieve some value from the class property shown above. But TS shows the error described in the code below.

What am I doing wrong?

export enum AmplitudeFeatureFlagNames {
  addTeamMembersFromUserMenu = 'addTeamMembersFromUserMenu',
  inAppHandRaiser = 'inAppHandRaiser',
}

type AmplitudeFeatureFlagWithPayload<Payload extends object = {}> = {
  key: string;
  payload?: Payload;
};

export type AmplitudeFeatureFlags = {
  [AmplitudeFeatureFlagNames.addTeamMembersFromUserMenu]: AmplitudeFeatureFlagWithPayload;
  [AmplitudeFeatureFlagNames.inAppHandRaiser]: AmplitudeFeatureFlagWithPayload;
};

class User {
  private amplitudeFeatureFlags: AmplitudeFeatureFlags | {} = {};

    getAmplitudeFeatureFlagPayload(flagName: AmplitudeFeatureFlagNames) {
      if (flagName in this.amplitudeFeatureFlags) {
    
    **//ERROR on the line below:**
    //Element implicitly has an 'any' type because expression of type 
   //'AmplitudeFeatureFlagNames' can't be used to index type '{} | 
    //AmplitudeFeatureFlags'.
    //Property '[AmplitudeFeatureFlagNames.addTeamMembersFromUserMenu]' does not exist on 
    //type '{} | AmplitudeFeatureFlags'.

        **return this.amplitudeFeatureFlags[flagName]?.payload;**
      }
  }
}

CodePudding user response:

It's because this.amplitudeFeatureFlags is not always of type AplitudeFeatureFlags. Your declaration is

private amplitudeFeatureFlags: AmplitudeFeatureFlags | {}

So typescript knows it might be of type {}, and thus {}[key: AmplitudeFeatureFlagNames] is of type any implicitly.

You'll want to change the declaration to something more descriptive:

private amplitudeFeatureFlags: Partial<AmplitudeFeatureFlags> = {}

Making your code:

export enum AmplitudeFeatureFlagNames {
  addTeamMembersFromUserMenu = 'addTeamMembersFromUserMenu',
  inAppHandRaiser = 'inAppHandRaiser',
}

type AmplitudeFeatureFlagWithPayload<Payload extends object = {}> = {
  key: string;
  payload?: Payload;
};

export type AmplitudeFeatureFlags = {
  [AmplitudeFeatureFlagNames.addTeamMembersFromUserMenu]: AmplitudeFeatureFlagWithPayload;
  [AmplitudeFeatureFlagNames.inAppHandRaiser]: AmplitudeFeatureFlagWithPayload;
};

class User {
  private amplitudeFeatureFlags: Partial<AmplitudeFeatureFlags> = {};

    getAmplitudeFeatureFlagPayload(flagName: AmplitudeFeatureFlagNames): AmplitudeFeatureFlagWithPayload['payload'] | undefined {
      if (flagName in this.amplitudeFeatureFlags) {
        return this.amplitudeFeatureFlags[flagName]?.payload;
      }
      return undefined
  }
}
  • Related