Strongly typing Twitter widget to get rid of member access errors

241 views Asked by At

I'm having difficulty strongly typing my Twitter widget.

At the moment, it throws me a bunch of errors including:

ESLint: Unsafe call of an any typed value.(@typescript-eslint/no-unsafe-call)
ESLint: Unsafe member access .catch on an any value.(@typescript-eslint/no-unsafe-member-access)
ESLint: Unsafe member access .createTweet on an any value.(@typescript-eslint/no-unsafe-member-access)
ESLint: Unsafe member access .finally on an any value.(@typescript-eslint/no-unsafe-member-access)
ESLint: Unsafe member access .then on an any value.(@typescript-eslint/no-unsafe-member-access)

I'd like to fix this by creating an interface for the twi, but I'm unsure what that would look like.

  loadTwitterWidget(): void {
    this.setLoadingStatus.emit(true);
    this.courseContentElementEmbedTweetService
      .loadScript()
      .pipe(take(1))
      .subscribe(
        // I want to create an interface for this
        (twitter) => {
          (this.tweet.nativeElement as HTMLElement).innerHTML = null;
          // Errors occur here
          twitter['widgets']
            .createTweet(this.courseContentElementEmbed.id, this.tweet.nativeElement, {
              ...this.tweetOptions,
            })
            .then((r) => {
              if (!r) {
                this.setErrorStatus.next();
              } else {
                this.setSuccessStatus.next();
              }
            })
            .catch((error) => this.logger.error(error))
            .finally(() => this.setLoadingStatus.emit(false));
        },
        (error) => this.logger.error(error)
      );
  }

So far I've tried the following:

export interface ICourseContentElementEmbedTweetWidget {
  widgets: {
    createTweet: unknown
  }
  [key: string]: string;
}

But I get the error TS2411: Property 'widgets' of type '{ createTweet: unknown; }' is not assignable to string index type '.

2

There are 2 answers

3
KrisztiƔn Balla On

If you define properties on your type that are different from the type of the index signature, you will get an error message.

The reason is that you could access the widgets in two ways:

  • object.widgets OR
  • object["widgets"]

which are the same, but would have different types in your code.

To solve this, you can define the type of the index signature as a union type of the property types:

export interface ICourseContentElementEmbedTweetWidget {
  widgets: {
    createTweet: unknown
  }
  [key: string]: string | { createTweet: unknown };
}

This is described in the TypeScript docs here: https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures

However I would advise not doing this, because now you will have to check the type or do a type assertion whenever accessing the indexer. If you can, remove the indexer and specify only the properties that are available.

2
Syed Mohib Uddin On

You can provide it as any like below or you can navigate to modules by pressing F12 if using vscode and search for createTweet you will get its data type there.

export interface ICourseContentElementEmbedTweetWidget {
  widgets: {
    createTweet: any
  }
  [key: string]: string;
}