Aller au contenu

Projet indépendant de R&D · Cologne

TypeScript et Node

Des schémas d'exécution comme source des types, les réglages de validation par défaut des frameworks, AsyncLocalStorage et les règles de dépendances.

Non normatif

Version du Companion
1.0
Se rapporte à COADF Core
2.2
Statut
À jour
Dernière relecture
Version du profil
1.0
Exemples de code
Les exemples de code suivront dans une révision ultérieure.

Les exemples de code suivront dans une révision ultérieure.

Propriétés d'architecture traitées

  • P-1Un schéma d'exécution comme contrat, le type statique qui en est dérivé et, dans le pattern de référence, une fabrique comme seul chemin vers une valeur vérifiée.
  • P-4Le contexte OpenTelemetry via AsyncLocalStorage, et l'identité d'audit comme champ obligatoire de chaque message et de chaque job.
  • P-5La provenance déclarée dans le schéma, et préservée par le sérialiseur de réponse.
  • P-6Des règles de dépendances et des contrôles de schéma dans l'intégration continue, chacun avec un échec planté.
  • P-7Des ports dans le paquet du domaine ; un paquet d'adaptateur par système externe.
  • P-8Une interface de politique au-dessus d'un moteur, via HTTP ou compilé en WebAssembly, avec la révision sur chaque décision.
  • P-2, P-3Seulement à la profondeur que COADF publie.

Intention d'architecture

TypeScript donne à la frontière un vocabulaire, et rien de son application. Les annotations de type ne changent jamais le comportement d'un programme à l'exécution : elles décrivent ce qu'une valeur devrait être et disparaissent avant l'exécution, tandis que les données qui arrivent d'un modèle, d'une file ou d'une requête ont la forme qu'elles ont. Les typages standard déclarent le résultat de JSON.parse comme any, que le compilateur laisse ensuite traiter comme n'importe quoi.

Dans cet écosystème, la frontière est donc le schéma d'exécution, et le type statique est dérivé du schéma, jamais l'inverse. Tout le reste de ce profil découle de ce renversement. Zod, Ajv, Fastify et NestJS sont des exemples : COADF n'en exige aucun, et tout validateur d'exécution qui refuse ce que le contrat ne déclare pas tient la propriété.

Correspondance technologique

TypeScript et Node: Correspondance technologique
Propriété d'architectureTypeScript et Node
Type de frontièreUn schéma d'exécution (Zod, ou JSON Schema avec Ajv) comme source, avec le type statique inféré à partir de lui. Le système de types de TypeScript est structurel : une valeur vérifiée qui ne doit pas être confondue avec une proposition a donc besoin d'une marque (brand), et seule une fabrique l'applique.
Validation à l'exécutionparse ou safeParse de chaque côté récepteur. Le parse de Zod lève une exception sur des données invalides, et safeParse renvoie un résultat à la place.
Clés inconnuesUn choix explicite par schéma. Dans Zod 4, z.object() retire les clés inconnues et z.strictObject() les rejette.
Validation du frameworkLes schémas de route de Fastify, validés avec Ajv et sérialisés avec fast-json-stringify ; ou le ValidationPipe de NestJS avec whitelist et forbidNonWhitelisted.
Règle d'architectureDes règles de dépendances contrôlées dans la CI : dependency-cruiser, des règles de frontière ESLint, ou des références de projet TypeScript qui font d'un import illégal une erreur de compilation.
Contexte d'exécutionOpenTelemetry JS, dont le gestionnaire de contexte pour Node est fondé sur AsyncLocalStorage.
Piste d'auditLe même schéma PostgreSQL via un driver ; des entrées écrites dans la transaction métier.
Isolation des normesDes interfaces de port dans le paquet du domaine ; chaque client de fournisseur cantonné à un paquet d'adaptateur dans le workspace.
PolitiqueOpen Policy Agent via HTTP, ou Rego compilé en WebAssembly et évalué dans le processus grâce au SDK JavaScript d'OPA ; la révision sur chaque décision.

Pattern de référence

Les exemples de code suivront dans une révision ultérieure. Ils sont reportés jusqu'à ce qu'une personne qui vérifie et travaille dans cet écosystème les ait lus, plutôt qu'écrits pour que les quatre profils se ressemblent. La structure ci-dessous est le pattern de référence que ces exemples mettront en œuvre.

Paquets

  • schemas contient les schémas d'exécution de chaque contrat : la proposition avec sa provenance, l'entrée d'audit avec les champs publiés, la décision de politique avec sa révision. Tous les autres paquets importent leurs types d'ici, inférés à partir des schémas.
  • inference appelle le modèle et renvoie le résultat de l'analyse de la réponse avec le schéma de proposition. Il ne peut pas importer records ou audit, et une règle de dépendances dans la CI l'affirme.
  • records exporte une fabrique qui prend une proposition et la vérification d'une personne nommée et renvoie une valeur vérifiée marquée. Le type de la marque ne peut pas être construit ailleurs sans cast, et une règle de lint interdit ce cast hors de ce paquet.
  • audit, classification avec son adaptateur de fournisseur, et policy suivent la même forme que dans les autres profils.

Les frontières à l'exécution

Chaque côté récepteur analyse : la route HTTP, le consommateur de messages, l'exécuteur de jobs et la fabrique du domaine. Un schéma de route dans Fastify ou un pipe dans NestJS ne couvre que le point d'entrée web.

Le SDK OpenTelemetry est chargé avant les propres modules de l'application. Une application en modules ES a besoin du hook de chargement d'OpenTelemetry pour l'instrumentation automatique, en plus du préchargement du SDK.

Modes de défaillance

  1. Une annotation de type prise pour une validation

    Caster le résultat de JSON.parse vers le type de proposition compile, et ne contrôle rien. Le cast est la frontière la plus courante dans le code TypeScript, et ce n'est pas une frontière.

  2. Retirer pris pour refuser

    Un objet Zod par défaut retire les clés inconnues. Une réponse qui se dit vérifiée n'est pas refusée ; l'affirmation est discrètement retirée, et le fait que le modèle en ait trop affirmé disparaît avec elle. Là où l'affirmation elle-même constitue une preuve, utiliser un objet strict et enregistrer le rejet.

  3. La conversion par défaut dans Fastify

    Les options Ajv par défaut de Fastify incluent coerceTypes, useDefaults et removeAdditional. Un nombre envoyé sous forme de texte arrive comme nombre, et une valeur manquante peut arriver comme valeur par défaut. Configurer explicitement le validateur pour les routes de frontière.

  4. La provenance perdue par le sérialiseur de réponse

    Avec un schéma de réponse, les propriétés que le schéma ne liste pas sont omises, sauf s'il autorise des propriétés supplémentaires. Un schéma de réponse écrit pour l'écran, sans la provenance, la retire de chaque réponse.

  5. Un pipe NestJS qui laisse tout passer

  6. Le contexte perdu à travers le travail asynchrone

    AsyncLocalStorage conserve des données pendant la durée de vie d'une requête ou d'une autre durée asynchrone, et suit les continuations que Node peut voir. Le travail qui revient depuis un callback mutualisé ou depuis la file propre à une bibliothèque peut arriver sans lui ; l'identité d'audit doit se trouver dans le message, et non être récupérée depuis le contexte.

  7. L'instrumentation automatique absente sans bruit

    Un service en modules ES démarré sans le hook de chargement fonctionne normalement, et les bibliothèques que le hook aurait instrumentées ne produisent aucun span. Rien n'échoue ; la trace est simplement plus courte que l'exécution.

  8. Une marque contrefaite par un cast

    Un cast vers le type vérifié compile n'importe où. La marque avec sa fabrique est une convention que le compilateur ne peut pas imposer à lui seul ; ce sont la règle de lint et la revue de code qui la font tenir.

  9. Deux versions des schémas partagés

    Le producteur et le consommateur dépendent de versions différentes du paquet schemas, et chacun valide correctement contre un contrat différent. Les tests de contrat entre les versions réellement déployées le détectent ; les tests unitaires, non.

Vérification

  • Test unitaire

    Réussit quand : Les réponses mal formées sont rejetées par le schéma de proposition : clé inconnue, type erroné, provenance manquante, attribut inattendu.

    Preuve de dents : Remplacer l'objet strict par un objet par défaut dans une branche jetable : le test de la clé inconnue échoue.

  • Test unitaire

    Réussit quand : Un test au niveau des types affirme qu'une proposition n'est pas assignable à une valeur vérifiée.

    Preuve de dents : Retirer la marque : le test au niveau des types ne compile plus.

  • Test d'architecture

    Réussit quand : Les règles de dépendances passent : aucun import de inference vers records ou audit, aucun client de fournisseur hors de son adaptateur.

    Preuve de dents : Planter l'import interdit : la CI échoue.

  • Test de contrat

    Réussit quand : La réponse de chaque route qui sert une proposition contient les champs de provenance.

    Preuve de dents : Retirer une propriété de provenance du schéma de réponse : le test échoue, parce que le sérialiseur l'a supprimée.

  • Test d'intégration

    Réussit quand : Avec un exportateur de spans en mémoire, le travail asynchrone apparaît dans la trace de la requête, et les entrées d'audit persistées portent une seule identité.

  • Test d'intégration

    Réussit quand : Les décisions de politique portent la révision du matériau de politique qui les a produites ; les réponses qui n'en ont pas sont refusées.

Réalisations alternatives

  • D'autres bibliothèques de schémas (Valibot, TypeBox avec Ajv, io-ts). La propriété est un schéma d'exécution qui est la source du type ; la bibliothèque est un choix.
  • Des transports fondés sur le schéma, comme GraphQL ou Protocol Buffers, où le contrat est un artefact séparé à partir duquel les deux côtés sont générés.
  • Un moteur de politiques dans le processus via WebAssembly, plutôt que via HTTP, pour supprimer le saut réseau ; l'exigence de révision ne change pas.

Compromis

  • Partir du schéma déplace la source de vérité hors des déclarations de types, ce que certaines équipes trouvent peu naturel ; partir des types laisse l'exécution sans protection.
  • Les validateurs compilés sont rapides et apportent des réglages par défaut qui convertissent et complètent ; la configuration la plus rapide n'est pas la plus stricte.
  • Les objets stricts rejettent davantage de ce que produit un modèle, et chaque rejet demande une décision sur ce qu'il faut enregistrer.
  • Un workspace de petits paquets rend les règles de dépendances exprimables, et coûte en outillage de build et de livraison.

Limites

  • Aucun code n'est publié pour ce profil dans Companion 1.0, et aucun exemple n'a été exécuté. Le comportement décrit est tiré de la documentation officielle actuelle, consultée le 11 septembre 2026, pour Zod 4, Fastify 5, NestJS, Node.js 24 et OpenTelemetry JS 2.
  • Rien ici ne montre comment la confiance est représentée, quand une revue est requise, ni comment la revue est organisée ; COADF ne publie pas ces parties de P-2 et P-3.

Ce que ce profil n'établit pas

Suivre ce profil n'établit ni la conformité réglementaire, ni une certification, ni une évaluation de la conformité, et COADF n'exige ni TypeScript ni Node.

Environnement de référence testé

Aucun exemple n'a été exécuté pour ce profil.

Sources

COADF Engineering Companion 1.0 · non normatif · se rapporte à COADF Core 2.2

Droits de publication réservés. Aucune licence publique n'est accordée à ce jour pour le COADF Engineering Companion 1.0 ni pour ses exemples de référence.

Statut de propriété intellectuelle et de publication