Génération de types avec types-codegen
@duplojs/types-codegen
est une librairie permettant de générer des types TypeScript à partir des routes de votre application. Elle est particulièrement utile pour la création de clients HTTP typés. vous pouvez consulter la documentation du client HTTP typé ici qui utilise les types générés par @duplojs/types-codegen
. Tous les exemples présentés dans cette section sont disponibles en entier ici.
Installation
Pour utiliser @duplojs/types-codegen
, vous devez l’installer en tant que dépendance de développement de votre projet.
npm install --save-dev "@duplojs/[email protected]"
Utilisation
Pour générer du typages à partir des routes de votre application, vous aurez besoin d’ajouter une commande dans votre fichier package.json
.
{
...,
"scripts": {
...,
"generate-types": "duplojs-types-codegen --import @duplojs/node/globals --include src/routes/index.ts --output duplojsTypesCodegen.d.ts"
},
...
}
Dans cet exemple :
- Une commande
generate-types
a étais ajouter dans le fichierpackage.json
.- La commande
duplojs-types-codegen
est utilisé pour générer les types.- L’option
--include
est utilisé pour spécifier le fichier d’entrée.- L’option
--output
est utilisé pour spécifier le fichier de sortie des types.
Il est également possible d’utiliser @duplojs/types-codegen
via npx
sans l’installer.
Options
@duplojs/types-codegen
propose plusieurs options pour personnaliser la génération des types.
Option | Alias | Description |
---|---|---|
--watch | -w | Permet de surveiller le fichier contenant les routes et de regénérer les types à chaque modification |
--import | - | Permet d’importer des modules nécessaires à l’exécution (comme @duplojs/node/globals ) |
--require | - | Permet d’importer des fichiers nécessaires à l’exécution, notamment ceux déclarant des variables globales |
--include | -i | Permet de spécifier le ou les fichiers à inclure dans la génération |
--output | -o | Permet de spécifier le fichier de sortie |
--exclude | -e | Permet d’exclure des routes de la génération |
Les options
--import
,--require
et--include
peuvent être utilisées de deux façons pour spécifier plusieurs fichiers :
- En séparant les fichiers par des virgules :
--require src/config.ts,src/env.ts
- En répétant l’option :
--require src/config.ts --require src/env.ts
Exemple de sortie
@duplojs/types-codegen
génère des types TypeScript à partir des routes de votre application. Voici un exemple de fichier de sortie :
type CodegenRoutes = ({
method: "GET";
path: "/products";
response: {
code: 200;
information: "products.found";
body: {
id: number;
name: string;
price: number;
quantity: number;
}[];
};
}) | ({
method: "GET";
path: "/users/{userId}";
params: {
userId: number;
};
response: {
code: 404;
information: "user.notfound";
body?: undefined;
} | {
code: 200;
information: "user.found";
body: {
id: number;
name: string;
email: string;
};
};
});
export { CodegenRoutes };
Source du typages
Le typage généré est basé sur les éléments de vos routes. Les composants qui enrichissent la génération sont :
- La méthode HTTP (GET, POST, PUT, etc.)
- Le chemin des routes (
/users/{id}
,/products
, etc.) - Les
ExtractStep
(route params, query params, body, etc.) - Les contrats de sortie des
Step
// preset checker
export const IWantUserExistById = createPresetChecker(
userExistCheck,
{
transformInput: userExistInput.id,
result: "user.exist",
catch: () => new NotFoundHttpResponse("user.notfound"),
indexing: "user",
},
makeResponseContract(NotFoundHttpResponse, "user.notfound"), // Response Contract CheckerStep
);
// route
useBuilder()
.createRoute("GET", "/users/{userId}") // method, path
.extract({ // ExtractStep
params: {
userId: zod.coerce.number(),
},
})
.presetCheck(
IWantUserExistById,
(pickup) => pickup("userId"),
)
.handler(
(pickup) => {
const { id, name, email } = pickup("user");
return new OkHttpResponse("user.found", {
id,
name,
email,
});
},
makeResponseContract(OkHttpResponse, "user.found", userSchema), // Response Contract HandlerStep
);
// output
type CodegenRoutes = ({
method: "GET";
path: "/users/{userId}";
params: {
userId: number;
};
response: {
code: 404;
information: "user.notfound";
body?: undefined;
} | {
code: 200;
information: "user.found";
body: {
id: number;
name: string;
email: string;
};
};
});
Dans cet exemple :
- Le type
CodegenRoutes
a été généré à partir de la route définie ci-dessus- Le preset checker
IWantUserExistById
possède un contrat de réponse intégré, qui est transmis à la route dans laquelle il est implémenté- La
HandlerStep
de la route possède également un contrat de réponse
Les routes héritent des contrats appartenant aux process qu’elles implémentent.
Ignoré les contrats d’une step
Il est possible d’indiquer au générateur qu’on ne souhaite pas prendre en compte les contrats d’une step. Pour cela, il suffit d’ajouté une instance de l’objet IgnoreByTypeCodegenDescription
dans les déscriptions de la step.
import { useBuilder, zod, OkHttpResponse, makeResponseContract } from "@duplojs/core";
import { IgnoreByTypeCodegenDescription } from "@duplojs/types-codegen";
useBuilder()
.createRoute("GET", "/users/{userId}")
.extract(
{
headers: {
authorization: zod.string(),
},
},
undefined,
new IgnoreByTypeCodegenDescription(),
)
.extract({
params: {
userId: zod.coerce.number(),
},
})
.presetCheck(
IWantUserExistById,
(pickup) => pickup("userId"),
new IgnoreByTypeCodegenDescription(),
)
.handler(
(pickup) => {
const { id, name, email } = pickup("user");
return new OkHttpResponse("user.found", {
id,
name,
email,
});
},
makeResponseContract(OkHttpResponse, "user.found", userSchema),
);
// output
type CodegenRoutes = ({
method: "GET";
path: "/users/{userId}";
params: {
userId: number;
};
response: {
code: 200;
information: "user.found";
body: {
id: number;
name: string;
email: string;
};
};
});
Dans cet exemple :
- L’
ExtractStep
sera ignorée et le type généré ne contiendra pas de headerauthorization
- La
CheckerStep
sera ignorée et le type généré ne contiendra pas de réponse associée à son contrat
Ignoré les contrats d’une route
Il est aussi possible d’indiquer au générateur qu’on souhaite ignorer une route. Pour cela, il suffit d’ajouter une instance de l’objet IgnoreByTypeCodegenDescription
dans les descriptions de la route.
import { useBuilder, zod, OkHttpResponse, makeResponseContract } from "@duplojs/core";
import { IgnoreByTypeCodegenDescription } from "@duplojs/types-codegen";
useBuilder(new IgnoreByTypeCodegenDescription())
.createRoute("GET", "/users/{userId}", new IgnoreByTypeCodegenDescription()) // same thing
.extract({
params: {
userId: zod.coerce.number(),
},
})
.presetCheck(
IWantUserExistById,
(pickup) => pickup("userId"),
)
.handler(
(pickup) => {
const { id, name, email } = pickup("user");
return new OkHttpResponse("user.found", {
id,
name,
email,
});
},
makeResponseContract(OkHttpResponse, "user.found", userSchema),
);
Dans cet exemple :
- La description
IgnoreByTypeCodegenDescription
peut être placée soit en argument duuseBuilder
soit en argument de la méthodecreateRoute
- Aucun type ne sera généré à partir de cette route
Tous les exemples d’ignorance de contrat sur les routes s’appliquent également aux process.
Utilsation sans la commande
Il est également possible d’utiliser @duplojs/types-codegen
sans la commande en important directement la fonction generateTypeFromRoutes
.
import { useRouteBuilder } from "@duplojs/core";
import { generateTypeFromRoutes } from "@duplojs/types-codegen";
import "./path-to-my-routes";
const routes = [...useRouteBuilder.getAllCreatedRoute()];
const generatedTypes = generateTypeFromRoutes(routes);
console.log(generatedTypes);
Dans cet exemple :
- Les routes sont récupérées à l’aide de
useRouteBuilder.getAllCreatedRoute()
.- Les routes sont importées à l’aide de
./path-to-my-routes
.- Les types sont générés à l’aide de
generateTypeFromRoutes
.- Les types générés sont affichés dans la console.