\begin{figure}[H] \begin{lstlisting}[language=JavaScript] export type InputType = { string: string, 'date-time': Date, number: number, checkbox: boolean, }; export type InputField = { defaultValue?: T; validate?: (value: T) => boolean; label?: string; inputType: keyof InputType; }; export class InputFieldBuilder { static from(inputType: K): InputField { // ... } // ... } /** * Represents an action that can be performed on the target device **/ export abstract class Action { static module: string; static action: string; abstract run(params: TInput): Promise; } /** * Returns the `Params` generic type in `Action` **/ export type ExtractActionParams> = TAction extends Action ? Params : never; \end{lstlisting} \caption{Exemple de types avancés en TypeScript (1/2)} \label{types} \end{figure} \begin{figure}[H] \begin{lstlisting}[language=JavaScript] /** * This type returns a narrowed-down version of `Record`, that requires that every value in `Params` * has a field attached to it. **/ export type MapActionParams = Params extends undefined | void | null ? unknown : { [Key in keyof Params]: Params[Key] extends InputType[keyof InputType] ? InputField : InputField; }; /** * Conditionally sets the `fields` property of `Request` to: * - if `TAction` is set to `unknown` (default), an optional `Record` * - if `TAction` is set to an `Action`, then it will extract the properties defined in that `Action`, * and require you to properly define their fields **/ export type RequestFields = TAction extends Action ? { fields: Record & MapActionParams>; } : { fields?: Record; }; /** * Represents a network request that will be sent to the device to perform the similarly-named Action. **/ export type Request = { action?: string; module?: string; } & RequestFields; // Exemple: class ShowMessageAction extends Action<{ message: string}, void> { run({message}): Promise { // show `message` } } const ShowMessageRequestFields: RequestFields = { module: 'system', action: 'showMessage', fields: { // Si on omet `message` ou si on utilise un autre type, une erreur est affichée message: InputFieldBuilder.from('string').build() } }; \end{lstlisting} \caption{Exemple de types avancés en TypeScript (2/2)} \end{figure}