You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
2.7 KiB

\begin{figure}[H]
\begin{lstlisting}[language=JavaScript]
export type InputType = {
string: string,
'date-time': Date,
number: number,
checkbox: boolean,
};
export type InputField<T = unknown> = {
defaultValue?: T;
validate?: (value: T) => boolean;
label?: string;
inputType: keyof InputType;
};
export class InputFieldBuilder {
static from<K extends keyof InputType>(inputType: K): InputField<InputType[K]> {
// ...
}
// ...
}
/**
* Represents an action that can be performed on the target device
**/
export abstract class Action<TInput, TOutput> {
static module: string;
static action: string;
abstract run(params: TInput): Promise<TOutput>;
}
/**
* Returns the `Params` generic type in `Action<Params, Result>`
**/
export type ExtractActionParams<TAction extends Action<unknown, unknown>> =
TAction extends Action<infer Params, unknown> ? 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<string, InputField>`, that requires that every value in `Params`
* has a field attached to it.
**/
export type MapActionParams<Params> = Params extends undefined | void | null
? unknown
: {
[Key in keyof Params]: Params[Key] extends InputType[keyof InputType]
? InputField<Params[Key]>
: InputField;
};
/**
* Conditionally sets the `fields` property of `Request` to:
* - if `TAction` is set to `unknown` (default), an optional `Record<string, InputField>`
* - 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> = TAction extends Action<unknown, unknown>
? {
fields: Record<string, InputField> & MapActionParams<ExtractActionParams<TAction>>;
}
: {
fields?: Record<string, InputField>;
};
/**
* Represents a network request that will be sent to the device to perform the similarly-named Action.
**/
export type Request<TAction = unknown> = {
action?: string;
module?: string;
} & RequestFields<TAction>;
// Exemple:
class ShowMessageAction extends Action<{ message: string}, void> {
run({message}): Promise<void> {
// show `message`
}
}
const ShowMessageRequestFields: RequestFields<ShowMessageAction> = {
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}