Accueil / Articles / Les victoires discrètes de TypeScript 6 et les habitudes en JavaScript des développeurs seniors

Les victoires discrètes de TypeScript 6 et les habitudes en JavaScript des développeurs seniors

Découvrez les fonctionnalités négligées de TypeScript 6, telles que la gestion explicite des ressources et les paramètres de type const, ainsi que les idiomes JavaScript sur lesquels comptent quotidiennement les ingénieurs seniors.

1228 mots

JavaScript moderne et TypeScript continuent d’évoluer de manières qui vont bien au-delà des fonctionnalités médiatisées ou des points listés dans les changelogs. Deux aspects pratiques sont particulièrement importants actuellement : les ajouts plus discrets et moins médiatisés de TypeScript 6, ainsi que les idiomes JavaScript courants qui distinguent les demandes de modification de haut niveau d’un simple code fonctionnel. Ces deux domaines relèvent en réalité de la même discipline — maîtriser suffisamment les outils pour choisir le bon plutôt que celui auquel on est habitué. Cet article aborde les deux sujets, en commençant par ce que TypeScript 6 a apporté de discret, puis en passant aux patterns JavaScript auxquels les ingénieurs expérimentés ont recours par défaut.

Mises à jour discrètes de TypeScript 6 dignes d’être adoptées

La plupart des articles sur TypeScript 6 se contentent d’indiquer que le mode strict et ES2025 sont désormais les paramètres par défaut. Il s’agit bien d’un changement important, mais il masque un ensemble de petites améliorations qui éliminent discrètement des solutions de contournement existantes depuis longtemps. Si vous ne lisez que les titres concernant tsconfig-default, vous manquez la partie la plus utile de cette mise à jour.

Nettoyage dont vous n’avez pas besoin de vous souvenir

Une source fréquente d’erreurs est l’oubli de fermer une connexion à une base de données ou de supprimer un écouteur. TypeScript 6 remédie à cela grâce à une gestion explicite des ressources, vous permettant de marquer une valeur afin qu’elle soit automatiquement nettoyée dès qu’elle quitte son champ d’application.

function readUserSession() {
  using session = openSession(); // auto-disposed at scope end
  const user = session.getUser();
  return user.name;
} // session.dispose() called automatically here

Cela élimine la nécessité d’utiliser des blocs try/finally dont la seule fonction était de garantir le nettoyage. L’ajout syntaxique est mineur, mais les avantages en termes de fiabilité sont considérables pour tout ce qui concerne des fichiers, des sockets ou des connexions ouvertes.

Types littéraux sans l’usage excessif de as const

Auparavant, pour conserver les types littéraux tels quels au sein d’une fonction générique, il fallait disperser as const un peu partout dans le code. TypeScript 6 introduit des paramètres de type const, qui conservent automatiquement l’inférence des types littéraux.

function createConfig<const T extends Record<string, unknown>>(config: T) {
  return config;
}

const config = createConfig({
  env: "production",
  features: ["auth", "billing"],
});
// config.env is "production", not string
// config.features is readonly ["auth", "billing"], not string[]

Si vous développez des clients API typés ou des créateurs d’actions Redux, cela élimine une grande partie du code générique as const dont vous auriez normalement besoin.

Réduction appropriée des types à l’intérieur de switch (true)

Une autre amélioration appréciable : les unions discriminées peuvent désormais être correctement réduites à l’intérieur d’une instruction switch (true), ce qui obligeait auparavant à utiliser des chaînes imbriquées de if/else pour faire comprendre les types au compilateur.

function area(shape: Shape): number {
  switch (true) {
    case shape.kind === "circle":
      return Math.PI * shape.radius ** 2; // narrowed to Circle
    case shape.kind === "rectangle":
      return shape.width * shape.height; // narrowed to Rectangle
  }
}

Avec ce changement, vous n’avez plus besoin d’abandonner switch simplement pour conserver la restriction de type intacte.

Temporal obtient des types de première classe

TypeScript 6 intègre également des types intégrés pour l’API Temporal, ce qui vous permet d’éviter de devoir gérer les particularités des Date et de leurs zones horaires à l’aide d’affirmations de type manuelles.

const meetingStart = Temporal.Instant.from("2026-04-06T10:00:00Z");
const localTime = meetingStart.toZonedDateTimeISO("America/Toronto");

Importations de sous-chemin qui fonctionnent réellement

Un autre problème, bien moins grave mais tout aussi agaçant, a également été corrigé : les importations de sous-chemin internes fonctionnent désormais correctement, sans nécessiter une longue chaîne de segments de chemin relatifs.

import { User } from "#/models/user.js";
// instead of ../../../models/user.js 🙃

Daniel Rosenwasser, responsable du développement de TypeScript, a décrit TS6 comme un pont délibéré vers la prochaine version 7 de TypeScript basée sur Go, ce qui indique que il ne s’agit pas de fonctionnalités expérimentales temporaires — elles sont conçues pour rester. Si votre équipe travaille sur des bases de code full-stack en JavaScript, React ou Next.js, adopter ces bonnes pratiques dès maintenant permettra d’éviter de nombreuses surprises à l’arrivée de TypeScript 7. Dans l’ensemble, TypeScript 6 ne se limite pas à de nouvelles valeurs par défaut pour le compilateur ; il offre également un traitement plus propre des ressources, une inférence de types plus précise et moins de solutions manuelles nécessaires. Essayer d’utiliser les paramètres de type using et const dans votre prochaine demande de fusion pourrait vous faire réaliser à quel point vous vous en passiez auparavant.

Bonnes pratiques JavaScript qui distinguent les développeurs expérimentés des autres

Connaître les nouvelles fonctionnalités de TypeScript n’est que la moitié de l’histoire. L’autre moitié concerne la manière dont le JavaScript lui-même est écrit au quotidien. Lorsqu’une demande de modification d’un ingénieur senior est plus lisible que celles des autres, cela tient rarement à de la ruse — c’est plutôt le résultat d’habitudes cohérentes appliquées sans hésitation.

Chaînage optionnel et fusion des valeurs nulles

Au lieu d’utiliser des chaînes comme user && user.profile && user.profile.name, le code écrit par des ingénieurs seniors fait appel au chaînage optionnel associé à la fusion des valeurs nulles.

const displayName = user?.profile?.name ?? 'Guest';

Cela permet une écriture concise, protège contre l’absence de valeurs, et ne provoque aucune erreur lors du refactoring du code environnant.

Déstructuration avec valeurs par défaut

La déstructuration des propriétés, des réponses API et des arguments de fonction — avec des valeurs par défaut judicieuses intégrées — est une pratique courante pour ces ingénieurs.

function createUser({ name, role = 'member', isActive = true }) {
  return { name, role, isActive };
}

Cela permet de documenter la structure attendue des données directement dans la signature de la fonction.

Async/Await au lieu de promesses enchaînées

L’usage de .then().then().catch() fonctionne encore, mais il ne s’adapte pas bien à l’augmentation de la complexité logique. Comparez cela avec une version async/await :

async function fetchOrders(userId) {
  try {
    const res = await fetch(`/api/orders/${userId}`);
    if (!res.ok) throw new Error('Failed to fetch orders');
    return await res.json();
  } catch (err) {
    console.error('Order fetch failed:', err);
    throw err;
  }
}

Le résultat s’affiche de haut en bas, ce qui facilite le débogage et les tests.

Méthodes d’array plutôt que boucles manuelles

L’utilisation de map, filter, reduce et find remplace la plupart des boucles for écrites manuellement.

const activeAdmins = users
  .filter((u) => u.isActive && u.role === 'admin')
  .map((u) => u.email);

Cela signifie moins de variables modifiables et moins d’erreurs dues à une erreur de comptage.

Types utilitaires plutôt que interfaces redondantes

Au lieu de redéfinir des interfaces presque identiques, les développeurs expérimentés en TypeScript utilisent des types utilitaires tels que Partial, Pick et Omit.

type UserFormInput = Pick<User, 'name' | 'email'> & Partial<Pick<User, 'phone'>>;

Cela permet de conserver une seule source de vérité, ce qui signifie que les modifications des schémas nécessitent des mises à jour en moins d’endroits.

Hooks et composition dans React

Des hooks personnalisés qui extraient et encapsulent de la logique apparaissent constamment dans des bases de code React matures.

function useDebouncedValue(value, delay = 300) {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debounced;
}

Un hook de ce type permet à la logique sous-jacente d’être réutilisée et testée indépendamment de tout composant spécifique.

Gestion structurée de l’état

Pour la gestion de l’état, de nombreuses équipes expérimentées préfèrent les slices de Redux Toolkit aux réducteurs écrits manuellement à l’aide d’instructions switch, car RTK réduit le code générique et offre gratuitement l’immutabilité grâce à Immer.

Lectures complémentaires