0

This repo is the types for the youtube api

https://www.npmjs.com/package/@types/youtube

What is the proper way to import these types into a vue2 project?

The following code complains as the type is not defined. But if i import the type ts complains and says missing dependency.

<template>
  <div ref="ytplayer" class="MYouTube"></div>
</template>

<style lang="scss" scoped>
.MYouTube {
  position: relative;
  margin: 0 auto;
  padding-bottom: 56.25%;

  .iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 0;
  }
}
</style>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import getYoutubeId from '@/utils/getYoutubeId';
import reframe from '@/utils/reframe';
import injectScript from '@/utils/injectScript';

@Component
export default class MYouTube extends Vue {
  @Prop({ required: true })
  url!: string;

  vidId = '';
  $refs!: {
    ytplayer: any
  };

  created () {
    const vidId = getYoutubeId(this.url);
    if (vidId) {
      this.vidId = vidId;
    }
    injectScript('https://www.youtube.com/iframe_api', () => {
      this.injectAndPlay();
    });
  }

  injectAndPlay () {
    new YT.Player(this.$refs.ytplayer, {
      videoId: this.vidId,
      playerVars: {
        'playsinline': 1
      },
      events: {
        'onReady': (event) => {
          event.target.playVideo();
          reframe(this.$refs.ytplayer);
        },
        'onStateChange': () => {
          console.log('do something');
        }
      }
    });
  }
}
</script>

I have a global.d.ts but in here I can only declare YT as any:

interface Window {
  YT: any
}

In the tsconfig:

    "typeRoots": [
      "node_modules/@types"
    ],

but this does not auto resolve :/

1 Answers1

1

Types

No need to add a typeRoots in tsconfig.json for this.

Import the types in the type declarations file as yt, and replace YT: any with YT: yt:

// global.d.ts
import yt from '@types/youtube'

// `yt` needs to be outside of `global` for some reason
interface Window {
  YT: yt;
}

declare global {
  interface Window {
    onYouTubeIframeAPIReady?: () => void;
  }
}

If using VS Code, make sure to restart the IDE so that the file is properly indexed.

ESLint

Configure the YT global (and restart your dev server if running):

// .eslintrc.js
module.exports = {
  globals: {
    YT: true,
  },
}

Example usage

<template>
  <div>
    <div ref="ytplayer"></div>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component
export default class extends Vue {
  vidId = 'M7lc1UVf-VE'

  mounted(): void {
    window.onYouTubeIframeAPIReady = () => {
      new YT.Player(this.$refs.ytplayer as HTMLElement, {
        videoId: this.vidId,
        playerVars: {
          playsinline: 1
        },
        events: {
          onReady(event: YT.PlayerEvent) {
            event.target?.playVideo()
          },
          onStateChange() {
            console.log('do something')
          }
        }
      })

      delete window.onYouTubeIframeAPIReady
    }

    const script = document.createElement('script')
    script.src = 'https://www.youtube.com/iframe_api'
    const firstScriptTag = document.getElementsByTagName('script')[0]
    firstScriptTag.parentNode?.insertBefore(script, firstScriptTag)
  }
}
</script>

GitHub demo

tony19
  • 125,647
  • 18
  • 229
  • 307
  • thanks for the answer, but your proposed solution does not work unless you mark skipLibCheck as true in the tsconfig. Marking this as true break the rest of the application type checking it seems. EG The following should fail: ``` const player = new YT.Player( document.getElementById('doesnotexist'), { events: 321, height: { a: 1 } } ); ``` –  Aug 18 '21 at 14:09
  • With the skip skipLibCheck as not true, typescript instantly complains again and does not allow the import of a types file. –  Aug 18 '21 at 14:11
  • https://stackoverflow.com/questions/37565709/how-to-use-namespaces-with-import-in-typescript –  Aug 18 '21 at 14:16
  • (i do not know the answer yet though :) ) –  Aug 18 '21 at 14:16