Skip to main content

Player Class and static members

The logic to select an appropriate player from the registered players relies on the implementation of a static method getSupportedTypes in the class definition. While typescript does not allow for static members to be defined in a interface such as PlayerInterface, it possible to enforce static members by creating a different interface that represents the type of a class as a function constructor. For this a decorator helper was created that makes explicit the implementation of the static functions expected in the player.

PlayerClass interface

Understanding the type of a class

The PlayerClass is an interface that represents the type of the class itself rather than the type of an instance object of a class. In other words, it acts as the type of an object that implements a constructor function.

To illustrate this with an example see the next class definition:

class MyClass {
echo = (msg: string) => { console.log(msg); }
}

If you create a new object with the new keyword, it will create a new instance of MyClass which will have a method echo.

const myClass: MyClass = new MyClass();
myClass.echo('Hello');

But we cannot do the following:

MyClass.echo('Hello'); // Error, MyClass does not have a static method echo

This happens because the type MyClass represents the type of the instances that you create with it. You can however define the type of the class MyClass itself as follows:

interface MyClassType {
new(): MyClass;
}

This represents the interface that implements the new function which returns an object of the type MyClass or in other words, an object that implements a constructor when you use the new keyword.

PlayerClass definition

The PlayerClass is defined as follows:

export interface PlayerClass<TPlayerLibrary = any> {
new(...args: any[]): PlayerInterface<TPlayerLibrary>;
// Required static methods
getSupportedTypes: () => readonly VideoType[];
}

This is a class with a constructor that returns an object that implements PlayerInterface and that implements a function getSupportedTypes. This function translates into a static function in the class definition.

Implementing the PlayerClass interface

To implement the PlayerClass interface we need a helper function that will add as a decorator for our class declaration.

The helper function playerStaticMembers looks as follows:

export function playerStaticMembers<TPlayerLibrary>() {
return <PC extends PlayerClass<TPlayerLibrary>>(constructor: PC) => { constructor; };
}

To use it as a decorator we use the syntax @playerStaticMembers<T>() before the class declaration.

@playerStaticMembers<PlayerLibrary>()
export class CustomPlayer implements PlayerInterface<PlayerLibrary> {}

In the example above PlayerLibrary represents the type of any player library or object used internally. This type is used by PlayerInterface (see more) but since typescript cannot infer it, we need to explicitly pass it to the decorator as well.

Now typescript will show errors if you miss implementing getSupportedTypes function or any other required static member that needs to be part of a class definition.

info

For more information about decorators refer to the typescript documentation