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.
For more information about decorators refer to the typescript documentation