Skip to content

Latest commit

 

History

History
792 lines (557 loc) · 54.8 KB

README.fr.md

File metadata and controls

792 lines (557 loc) · 54.8 KB

Definitely Typed

Le référentiel des définitions de type TypeScript de haute qualité.

Vous pouvez également lire ce README en Español, 한국어, Русский, 简体中文, Português, Italiano, 日本語 et English!

Lien vers le Manuel de l'administrateur

!!! Important ! Ce dépôt a récemment changé de structure ! !!!

Definitely Typed est récemment passé sur un véritable monorepo pnpm; vous voudriez peut-être relire ce document pour connaître les changements apportés à la structure des packages dans ce dépôt.

Au minimum, vous voudriez peut-être faire un git clean -fdx sur le dépôt (ou node ./scripts/clean-node-modules.js sur Windows) pour nettoyer node_modules et exécuter pnpm install --filter . pour installer la racine du workspace. Voir les sections suivantes pour plus d'informations sur pnpm install.

État actuel

Cette section permet de suivre l'état de santé du référentiel et du processus de publication. Elle peut être utile aux contributeurs qui rencontrent des problèmes avec leurs PR et leurs packages.

Si quelque chose semble incorrect ou si l'un des éléments ci-dessus échoue, merci de nous le faire savoir dans le canal Definitely Typed sur le serveur Discord de la Communauté TypeScript.

Que sont les fichiers de déclaration et comment les obtenir ?

Voir le Manuel TypeScript.

npm

C'est la méthode privilégiée. Par exemple :

npm install --save-dev @types/node

Pour installer des types d'un module scopé, remplacez le @ par deux underscore après le scope. Par exemple, pour installer des types pour @babel/preset-env :

npm install --save-dev @types/babel__preset-env

Les types devraient alors être automatiquement inclus par le compilateur. Vous pourriez avoir besoin d'ajouter une référence types si vous n'utilisez pas de modules :

/// <reference types="node" />

Plus d'informations dans le manuel.

Pour un package npm "foo", les types pour celui-ci seront dans "@types/foo".

Si votre package spécifie des types avec la clé types ou typings dans son package.json, le registre npm affichera que le package a des bindings disponibles comme ceci :

image

Si vous ne trouvez toujours pas les types, recherchez simplement les fichiers ".d.ts" dans le package et incluez-les manuellement avec /// <reference path="" />.

Support de version

Definitely Typed ne teste que les packages sur des versions de TypeScript datant de moins de 2 ans.

Anciennes versions de TypeScript

Les packages @types ont des tags pour les versions de TypeScript qu'ils supportent explicitement, de sorte que vous pouvez généralement obtenir des versions plus anciennes des packages qui précèdent la fenêtre de 2 ans. Par exemple, si vous lancez npm dist-tags @types/react, vous verrez que TypeScript 2.5 peut utiliser les types pour react@16.0, alors que TypeScript 2.6 et 2.7 peuvent utiliser les types pour react@16.4 :

Tag Version
latest 16.9.23
ts2.0 15.0.1
... ...
ts2.5 16.0.36
ts2.6 16.4.7
ts2.7 16.4.7
... ...

TypeScript 1.*

  • Télécharger manuellement depuis la branche master de ce dépôt et les placer dans votre projet
  • Typings (utilisez les alternatives préférées, typings est déprécié)
  • NuGet (utilisez les alternatives préférées, la publication des types DT de Nuget a été désactivée)

Vous pourriez avoir besoin d'ajouter le manuel references.

Comment puis-je contribuer ?

Definitely Typed ne fonctionne que grâce aux contributions d'utilisateurs comme vous !

Testing

Avant de partager votre amélioration avec le monde, utilisez les types vous-même en créant un fichier typename.d.ts dans votre projet et en remplissant ses exports :

declare module "libname" {
    // Types à l'intérieur ici
    export function helloWorldMessage(): string;
}

Test d'édition d'un package existant

Vous pouvez éditer les types directement dans node_modules/@types/foo/index.d.ts pour valider vos changements, puis apporter les changements à ce repo avec les étapes ci-dessous.

Alternativement, vous pouvez utiliser module augmentation pour étendre les types existants du module DT ou utiliser la technique declare module ci-dessus qui remplacera la version dans node_modules.

Ajouter des tests à un nouveau package

Ajoutez-le à votre tsconfig.json :

"baseUrl": "types",
"typeRoots": ["types"],

Créez types/foo/index.d.ts contenant les déclarations pour le module "foo". Vous devriez maintenant être capable d'importer "foo" dans votre code et il sera dirigé vers la nouvelle définition de type. Ensuite, compilez et exécutez le code pour vous assurer que votre définition de type correspond bien à ce qui se passe à l'exécution.

Une fois que vous avez testé vos définitions avec du code réel, faites une PR puis suivez les instructions pour modifier un package existant ou créer un nouveau package.

Faire une demande de pull request

Une fois que vous avez testé votre package, vous pouvez le partager sur Definitely Typed.

Tout d'abord, forkez ce dépôt, clonez le, installez node, et lancez npm install. Notez que pnpm install installera l'intégralité du dépôt, y compris des packages que vous ne modifiez peut-être pas. Si vous souhaitez installer uniquement un sous-ensemble, vous pouvez lancer pnpm install -w --filter "{./types/foo}..." pour installer @types/foo et toutes ses dépendances. Si vous avez besoin de lancer des tests de packages qui dépendent de @types/foo, vous pouvez lancer pnpm install -w --filter "...{./types/foo}..." pour récupérer tous les packages associés nécessaires aux tests.

Note

Si vous utilisez Windows, vous constaterez peut-être que git clean ne supprime pas le répertoire node_modules ou se bloque lors de cette opération. Si vous devez supprimer node_modules, vous pouvez lancer pnpm clean-node-modules pour réinitialiser le dépôt.

Nous utilisons un bot pour permettre à un grand nombre de pull requests de DefinitelyTyped d'être traitées entièrement en libre-service. Vous pouvez en savoir plus sur pourquoi et comment ici. Voici une référence pratique montrant le cycle de vie de pull request à DT :

Partial clone

Vous pouvez cloner l'ensemble du dépôt comme d'habitude, mais il est volumineux et comprend un énorme répertoire de packages de type.

Vous pouvez cloner l'ensemble du dépôt comme d'habitude, mais il est volumineux et comprend un énorme répertoire de packages de type. Cela prendra du temps à cloner et peut s'avérer inutilement lourd.

Pour un clone plus facile à gérer qui inclut seulement les packages de type qui vous concernent, vous pouvez utiliser les fonctionnalités de git sparse-checkout, --filter, et --depth. Cela réduira le temps de clonage et améliorera les performances de git.

⚠️ Ceci nécessite au minimum git version 2.27.0, qui est probablement plus récent que la version par défaut sur la plupart des machines. Des procédures plus complexes sont disponibles dans les versions plus anciennes, mais ne sont pas couvertes par ce guide.

  1. git clone --sparse --filter=blob:none <forkedUrl>
    • --sparse initialise le fichier sparse-checkout afin que le répertoire de travail ne contienne au départ que les fichiers situés à la racine du référentiel.
    • --filter=blob:none exclura des fichiers, les récupérant uniquement en cas de besoin.
  2. git sparse-checkout add types/<type> types/<dependency-type> ...

Modifier un package existant

Quand vous faites une PR pour éditer un package existant, dt-bot devrait @-mentionner les auteurs du package. S'il ne le fait pas, vous pouvez le faire vous-même dans un commentaire associé à la PR.

Créer un nouveau package

Si vous êtes l'auteur de la lib et que votre package est écrit en TypeScript, regroupez les fichiers de déclaration autogénérés dans votre package au lieu de le publier sur Definitely Typed. Vous pouvez également générer des fichiers de déclaration à partir de fichiers JavaScript, en utilisant JSDoc pour les annotations de type.

Si vous ajoutez des typages pour un package npm, créez un répertoire avec le même nom. Si le package pour lequel vous ajoutez des typages n'est pas sur npm, assurez-vous que le nom que vous choisissez pour lui n'entre pas en conflit avec le nom d'un package sur npm. (Vous pouvez utiliser npm info <mon-package> pour vérifier l'existence du package <mon-package>).

Votre package doit avoir cette structure :

Fichier Objectif
index.d.ts Il contient les typages du package.
<mon-package>-tests.ts Il contient un exemple de code qui teste les typages. Ce code ne s'exécute pas, mais il est vérifié.
tsconfig.json Cela vous permet d'exécuter tsc à l'intérieur du package.
.eslintrc.json (Rarement) Nécessaire uniquement pour désactiver les règles de lint écrites pour eslint.
package.json Contient les métadonnées du package, y compris son nom, sa version et ses dépendances.
.npmignore Spécifie quels fichiers doivent être inclus dans le package.

Vous pouvez les générer en lançant npx dts-gen --dt --name <mon-package> --template module. Voir toutes les options sur dts-gen.

Si vous avez des fichiers .d.ts en plus de index.d.ts, assurez-vous qu'ils sont référencés soit dans index.d.ts soit dans les tests.

Les membres de Definitely Typed surveillent régulièrement les nouveaux PRs, bien qu'il faille garder à l'esprit que le nombre d'autres PRs peut ralentir les choses.

Pour un bon exemple de package, voir base64-js.

Supprimer un package

Lorsqu'un package bundles à ses propres types, les types doivent être supprimés de Definitely Typed pour éviter toute confusion.

Vous pouvez le supprimer en lançant npm run not-needed -- <nomDuPackage> <commeVersion> [<nomDeLaLib>].

  • <nomDuPackage> : C'est le nom du répertoire à supprimer.
  • <commeVersion> : Un stub sera publié dans @types/<nomDuPackage> avec cette version. Elle doit être supérieure à toute version actuellement publiée, et doit être une version de <nomDeLaLib> sur npm.
  • <nomDeLaLib> : Nom du package npm qui remplace les types de Definitely Typed. Habituellement, il est identique à <nomDuPackage>, dans ce cas vous pouvez l'omettre.

Si un package n'a jamais été sur Definitely Typed, il n'a pas besoin d'être ajouté à notNeededPackages.json.

Exécution des tests

Testez vos modifications en lançant npm test <package à tester><package à tester> est le nom de votre package. Vous devez l'exécuter depuis le répertoire DefinitelyTyped car les package.json individuels ne définissent pas de scripts de test.

Ce script utilise dtslint pour lancer le compilateur TypeScript sur vos fichiers dts.

Une fois que tous vos changements sont prêts, lancez npm run test-all pour voir comment vos changements affectent les autres modules.

@arethetypeswrong/cli (attw) checks

dtslint inclut des vérifications de format de module et de configuration package.json à partir de @arethetypeswrong/cli. Les vérifications ne s'exécutent que si un package d'implémentation compatible avec SemVer-major peut être trouvé sur npm pour être comparé au package DefinitelyTyped. (Les packages DefinitelyTyped marqués comme nonNpm dans leur package.json sont ignorés.)

De nombreux packages échouent actuellement aux vérifications attw et doivent être corrigés. Pour nous permettre de progresser de manière incrémentale, les vérifications attw échouées ne font pas échouer l'exécution de dtslint lorsque le package est listé dans failingPackages dans attw.json, mais elles seront toujours signalées dans la sortie de pnpm test my-package. Si vous corrigez le package, retirez-le de failingPackages afin que les vérifications attw puissent commencer à faire échouer les exécutions de dtslint.

Tous les problèmes signalés par attw ont une documentation liée dans la sortie. Voici quelques règles générales pour éviter les problèmes :

  • Le package.json dans le package DefinitelyTyped doit avoir des champs type et exports correspondants si le package d'implémentation les utilise dans son package.json. Par exemple, si un package.json d'implémentation ressemble à :

    {
        "name": "my-package",
        "version": "1.0.1",
        "type": "module",
        "main": "dist/cjs/index.cjs",
        "exports": {
            ".": {
                "import": "./dist/esm/index.js",
                "require": "./dist/cjs/index.cjs"
            },
            "./subpath": {
                "import": "./dist/esm/subpath.js",
                "require": "./dist/cjs/subpath.cjs"
            }
        }
    }

    alors le package.json dans DefinitelyTyped devrait ressembler à ceci :

    {
        "name": "@types/my-package",
        "version": "1.0.9999",
        "type": "module",
        "types": "index.d.ts",
        "exports": {
            ".": {
                "import": "./index.d.ts",
                "require": "./index.d.cts"
            },
            "./subpath": {
                "import": "./subpath.d.ts",
                 "require": "./subpath.d.cts"
            }
        }
    }

    Notez que chaque sous-chemin exports est reflété, et chaque fichier JavaScript a un fichier de déclaration correspondant avec une extension de fichier correspondante à un fichier .d.ts d'un fichier .js, et non un fichier .mjs ou .cjs !

  • Lorsque le package d'implémentation utilise module.exports = ..., le package DefinitelyTyped doit utiliser export =, et non export default. (Alternativement, si le module.exports est juste un objet de propriétés nommées, le package DefinitelyTyped peut utiliser une série d'exports nommés.) L'obstacle le plus courant pour corriger ce problème est la confusion sur la façon d'exporter des types en plus de l'exportation principale. Par exemple, supposons que ces types utilisent incorrectement export default :

    export interface Options {
        // ...
    }
    export default function doSomething(options: Options): void;

    Changer export default en export = crée une erreur :

    export interface Options {
        // ...
    }
    declare function doSomething(options: Options): void;
    export = doSomething;
    // ^^^^^^^^^^^^^^^^^
    // Error: An export assignment cannot be used in a module with other exported elements.

    Pour résoudre cela, déplacez les types à l'intérieur d'un namespace portant le même nom que la fonction :

    declare namespace doSomething {
        export interface Options {
            // ...
        }
    }
    declare function doSomething(options: doSomething.Options): void;
    export = doSomething;

Si vous avez besoin d'aide pour résoudre un problème, veuillez demander dans le canal DefinitelyTyped sur le serveur Discord de la communauté TypeScript.

Nommage

Si vous ajoutez des types pour un package npm, créez un répertoire portant le même nom. Si le package pour lequel vous ajoutez des types n'est pas sur npm, assurez-vous que le nom que vous choisissez pour lui n'entre pas en conflit avec le nom d'un package sur npm. (Vous pouvez utiliser npm info <mon-package> pour vérifier l'existence du package <mon-package>).

Dans de rares occasions, nonNpm peut être défini sur "conflict", ce qui indique qu'il existe un package sur npm avec le même nom, mais que les types sont intentionnellement en conflit avec ce package. Cela peut être vrai pour les packages qui définissent un environnement comme @types/node ou pour des packages factices comme aws-lambda. Évitez d'utiliser "conflict" autant que possible.

<mon-package>-tests.ts

Il devrait y avoir un fichier <mon-package>-tests.ts, qui est considéré comme votre fichier de test, avec tous les fichiers *.ts qu'il importe. Si vous ne voyez aucun fichier de test dans le dossier du module, créez un fichier <mon-package>-tests.ts. Ces fichiers sont utilisés pour valider l'API exportée depuis les fichiers *.d.ts qui sont livrés en tant que @types/<mon-package>. Ils ne sont pas eux-mêmes expédiés.

Les changements apportés aux fichiers *.d.ts doivent inclure un changement correspondant au fichier *.ts qui montre l'API utilisée, afin que quelqu'un ne casse pas accidentellement le code dont vous dépendez. Par exemple, cette modification d'une fonction dans un fichier .d.ts ajoute un nouveau paramètre à une fonction :

index.d.ts:

- export function twoslash(body: string): string
+ export function twoslash(body: string, config?: { version: string }): string

<mon-package>-tests.ts:

import {twoslash} from "./"

// $ExpectType string
const result = twoslash("//")

+ // Handle options param
+ const resultWithOptions = twoslash("//", { version: "3.7" })
+ // When the param is incorrect
+ // @ts-expect-error
+ const resultWithOptions = twoslash("//", {  })

Si vous vous demandez par où commencer avec le code de test, les exemples dans le README du module sont un bon point de départ.

Vous pouvez valider vos changements avec npm test <package à tester> depuis la racine de ce repo, qui prend en compte les fichiers modifiés.

Utilisez $ExpectType pour affirmer qu'une expression est d'un type donné, et @ts-expect-error pour affirmer qu'il s'agit d'une erreur de compilation. Exemples :

// $ExpectType void
f(1);

// @ts-expect-error
f("one");

Pour plus de détails, voir le readme de dtslint.

Linter: .eslintrc.json

Si, pour une raison quelconque, une règle de lint doit être désactivée, désactivez-la pour une ligne spécifique :

// eslint-disable-next-line no-const-enum
const enum Const {
    One,
}
const enum Enum { // eslint-disable-line no-const-enum
    Two,
}

Vous pouvez toujours désactiver les règles avec un fichier .eslintrc.json, mais vous ne devriez pas le faire dans les nouveaux packages. Désactiver les règles pour l'ensemble du package rend la révision plus difficile.

tsconfig.json

tsconfig.json doit avoir noImplicitAny, noImplicitThis, strictNullChecks, et strictFunctionTypes défini à true.

Vous pouvez éditer le fichier tsconfig.json pour ajouter de nouveaux fichiers de test, pour ajouter "target" : "es6" (nécessaire pour les fonctions asynchrones), pour ajouter à "lib", ou pour ajouter l'option de compilateur "jsx".

esModuleInterop/allowSyntheticDefaultImports

TL;DR : esModuleInterop et allowSyntheticDefaultImports ne sont pas autorisés dans votre tsconfig.json.

Ces options permettent d'écrire une importation par défaut pour une exportation CJS, modélisant l'interopérabilité intégrée entre les modules CJS et ES dans Node et dans certains bundlers JS:

// component.d.ts
declare class Component {​​​​​}​​​​​
// CJS export, modeling `module.exports = Component` in JS
export = Component;

// index.d.ts
// ESM default import, only allowed under 'esModuleInterop' or 'allowSyntheticDefaultExports'
import Component from "./component";

Puisque la validité à la compilation de l'import dans index.d.ts dépend de paramètres de compilation spécifiques, dont les utilisateurs de vos types n'héritent pas, l'utilisation de ce pattern dans DefinitelyTyped forcerait les utilisateurs à changer leurs propres paramètres de compilation, ce qui pourrait être incorrect pour leur environnement d'exécution. Au lieu de cela, vous devez écrire un import CJS pour un export CJS afin d'assurer une compatibilité généralisée et indépendante de la configuration :

// index.d.ts
// CJS import, modeling `const Component = require("./component")` in JS
import Component = require("./component");

package.json

Ce fichier est requis et doit suivre ce modèle :

{
    "private": true,
    "name": "@types/PACKAGE-NAME",
    "version": "1.2.9999",
    "projects": [
        "https://aframe.io/"
    ],
    "dependencies": {
        "@types/DEPENDENCY-1": "*",
        "@types/DEPENDENCY-2": "*"
    },
    "devDependencies": {
        "@types/PACKAGE-NAME": "workspace:."
    },
    "owners": [
        {
            "name": "Your Name Here",
            "githubUsername": "ghost"
        }
    ]
}

Un package.json spécifie toutes les dépendances, y compris les autres packages @types.

Vous devez ajouter les dépendances non-@types à la liste des dépendances externes autorisées. Pikaday est un bon exemple. Ces ajouts sont approuvés par un mainteneur, ce qui nous donne l'occasion de nous assurer que les packages @types ne dépendent pas de packages malveillants.

Si le package d'implémentation utilise ESM et spécifie "type" : "module", alors vous devez ajouter un package.json avec la même chose :

{
    "type": "module"
}

Ceci s'applique également si le package d'implémentation a exports dans son package.json.

Peer dependencies

Definitely Typed autorise les peerDependencies dans package.json. Les peer dependencies peuvent aider à prévenir les situations où un gestionnaire de package installe de manière inattendue des versions trop récentes ou plusieurs versions du même package. Cependant, les peer dependencies ont des inconvénients ; les gestionnaires de packages diffèrent dans leur gestion des peer dependencies (par exemple, yarn ne les installe pas automatiquement, npm nécessite --legacy-peer-deps pour les incompatibilités). Ainsi, les PR introduisant de nouvelles peer dependencies nécessitent l'approbation d'un mainteneur et doivent être limitées à des circonstances spécifiques.

En général, les packages de types ne devraient avoir une peer dependency que si le package en amont a une peer dependency sur le même package (ou ses types). Par exemple, un package DT pour un composant React peut spécifier une peer dependency sur @types/react@*, car le consommateur aura besoin d'installer @types/react pour utiliser JSX en premier lieu. Si le consommateur installe @types/react@16 dans son projet, mais qu'une version plus récente de @types/react est disponible sur npm, la peer dependency peut aider le gestionnaire de packages à choisir @types/react@16 au lieu de cette version plus récente. De même, chai-as-promised a une peer dependency sur chai, donc @types/chai-as-promised devrait avoir une peer dependency sur @types/chai.

Il existe certains cas où le package en amont n'a pas de peer dependency sur le package de types, mais une peer dependency est toujours appropriée. Ce sont généralement des cas où le package en amont étend un autre package et suppose qu'il existe, donc devrait avoir déclaré une peer dependency car il étend un autre package, mais ne l'a pas fait. Par exemple, chai-match-pattern étend chai, mais ne déclare pas de peer dependency sur chai, mais en a besoin pour fonctionner. @types/chai-match-pattern devrait avoir une peer dependency sur @types/chai.

Si un package expose simplement des types d'un autre package dans le cadre de son API en raison d'une dépendance régulière dans le package en amont, il ne devrait pas utiliser une peer dependency. Par exemple, express a qs dans ses "dependencies". Lorsque les utilisateurs installent express, ils n'ont pas besoin d'installer manuellement qs. De même, @types/express a @types/qs dans ses "dependencies". Il serait incorrect de déclarer @types/qs comme une peer dependency de @types/express, car cela obligerait certains consommateurs en aval à installer manuellement @types/qs.

.npmignore

Ce fichier définit quels fichiers doivent être inclus dans chaque package @types. Il doit prendre une forme spécifique. Pour les packages avec une seule version dans le dépôt :

*
!**/*.d.ts
!**/*.d.cts
!**/*.d.mts
!**/*.d.*.ts

Ce qui signifie "ignorer tous les fichiers, mais ne pas ignorer les fichiers de déclaration". Pour les packages qui ont plus d'une version dans le dépôt, la version "la plus récente" (au niveau supérieur) devrait contenir quelque chose comme :

*
!**/*.d.ts
!**/*.d.cts
!**/*.d.mts
!**/*.d.*.ts
/v15/
/v16/
/v17/

Ce qui est identique au précédent .npmignore mais en ignorant chaque répertoire enfant versionné.

La CI échouera si ce fichier contient des contenus incorrects et fournira la valeur attendue. Peu importe ce que contient ce fichier, le publisher ne publiera que les fichiers de déclaration.

Erreurs courantes

  • Tout d'abord, suivez les conseils du manuel.
  • Formatage : dprint est configuré sur ce dépôt, vous pouvez donc lancer pnpm dprint fmt -- 'path/to/package/**/*.ts'.
    • Envisagez d'utiliser le fichier .vscode/settings.template.json de VS Code (ou l'équivalent pour d'autres éditeurs) pour formater à la sauvegarde avec l'extension dprint pour VS Code.
  • function sum(nums: number[]): number: Utilisez ReadonlyArray si une fonction n'écrit pas dans ses paramètres.
  • interface Foo { new(): Foo; }: Cela définit un type d'objets qui peuvent être modifiés. Vous voudrez probablement declare class Foo { constructor(); }.
  • const Class: { new(): IClass; }: Il est préférable d'utiliser une déclaration de classe class Class { constructor(); } plutôt qu'une constante modifiable.
  • getMeAT<T>(): T: Si un paramètre de type n'apparaît dans les types d'aucun paramètre, il ne s'agit pas vraiment d'une fonction générique, mais simplement d'une assertion de type déguisée. Il est préférable d'utiliser une assertion de type réelle, par exemple getMeAT() as number. Exemple où un paramètre de type est acceptable : function id<T>(value: T): T;. Exemple où il n'est pas acceptable : function parseJson<T>(json: string): T;. Exception : new Map<string, number>() est OK.
  • L'utilisation des types Function et Object n'est presque jamais une bonne idée. Dans 99% des cas, il est possible de spécifier un type plus spécifique. Les exemples sont (x: number) => number pour les fonctions et { x: number, y: number } pour les objets. S'il n'y a aucune certitude sur le type, any est le bon choix, pas Object. Si la seule chose connue à propos du type est qu'il s'agit d'un objet, utilisez le type object, pas Object ou { [key: string]: any }.
  • var foo: string | any: Lorsque any est utilisé dans un type union, le type résultant est toujours any. Ainsi, bien que la partie string de cette annotation de type puisse look utile, elle n'offre en fait aucune vérification de type supplémentaire par rapport à l'utilisation simple de any. Selon l'intention, les alternatives acceptables pourraient être any, string, ou string | object.

Propriétaires de définition

TL;DR : ne pas modifier .github/CODEOWNERS, toujours modifier la liste des propriétaires dans package.json.

DT a le concept de "propriétaires de définition" qui sont des personnes qui veulent maintenir la qualité des types d'un module particulier.

  • En vous ajoutant à la liste, vous serez notifié (via votre nom d'utilisateur GitHub) chaque fois que quelqu'un fera une pull request ou une issue concernant le package.
  • Vos reviews de PR auront une plus grande importance pour le bot qui maintient ce repo.
  • Les mainteneurs de DT font confiance aux propriétaires des définitions pour assurer un écosystème stable, ne vous ajoutez pas à la légère.

Pour vous ajouter en tant que propriétaire d'une définition, modifiez le tableau owners dans package.json :

"owners": [
    {
        "name": "Some Person",
        "githubUsername": "somebody"
    },
    {
        "name": "Some Corp",
        "url": "https://example.org"
    }
]

Notez que cette liste n'est pas utilisée pour créditer les contributions; il n'est utilisé que pour gérer les reviews des PR.

Une fois par semaine, les propriétaires de définitions sont synchronisés avec le fichier .github/CODEOWNERS qui est notre source de vérité.

L'histoire de Definitely Typed

Definitely Typed est l'un des dépôts les plus actifs sur GitHub. Vous vous êtes peut-être demandé comment le projet a vu le jour. Un historique de Definitely Typed existe, il a été réalisé par @johnnyreilly. Il raconte les premiers jours de Definitely Typed, depuis un dépôt créé par @borisyankov, jusqu'au moment où il est devenu un élément central de l'écosystème TypeScript. Vous pouvez lire l'histoire de Definitely Typed ici.

FAQ

Quelle est la relation exacte entre ce dépôt et les packages @types sur npm ?

La branche master est automatiquement publiée dans le scope @types sur npm grâce à DefinitelyTyped-tools.

J'ai soumis une pull request. Dans combien de temps sera-t-elle fusionnée ?

Cela dépend, mais la plupart des pull requests seront fusionnées en une semaine. Certains PR peuvent être fusionnés par les propriétaires d'un module, et ils peuvent être fusionnés beaucoup plus rapidement. En gros :

Les PRs qui ne modifient que les types d'un module, et qui ont des changements de tests correspondants seront fusionnés beaucoup plus rapidement.

Les PRs qui ont été approuvés par un auteur listé dans l'en-tête de la définition sont généralement fusionnés plus rapidement ; les PRs pour de nouvelles définitions prendront plus de temps car ils nécessitent plus de révision de la part des mainteneurs. Chaque PR est révisé par un membre de l'équipe TypeScript ou Definitely Typed avant d'être fusionné, donc soyez patient car des facteurs humains peuvent causer des retards. Consultez le Pull Request Status Board pour voir les progrès réalisés par les mainteneurs sur les PRs ouverts.

J'aimerais apporter une modification à un projet très populaire, pourquoi sont-ils traités différemment ?

Pour les modifications apportées à des modules très populaires, par exemple Node/Express/Jest, qui sont téléchargés plusieurs millions de fois par semaine sur npm, les exigences en matière de contributions sont un peu plus élevées. Les modifications apportées à ces projets peuvent avoir des effets considérables sur l'écosystème, et nous les traitons donc avec beaucoup d'attention. Ces modules requièrent à la fois l'approbation d'un mainteneur de DT et le soutien enthousiaste des propriétaires du module. La barre pour réussir cela peut être assez haute, et souvent les PRs peuvent s'essouffler parce qu'il n'y a pas de champion. Si vous constatez que personne ne s'engage, essayez de réduire la portée de votre PR.

Mon PR est fusionné ; quand le package npm @types sera-t-il mis à jour ?

Les packages npm devraient être mis à jour dans les minutes qui suivent. Si cela fait plus d'une heure, mentionnez le numéro de PR sur le canal Definitely Typed sur le serveur Discord de la communauté TypeScript et le mainteneur actuel demandera au bon membre de l'équipe d'enquêter.

J'écris une définition qui dépend d'une autre définition. Dois-je utiliser <reference types="" /> ou un import ?

Si le module auquel vous faites référence est un module externe (qui utilise export), utilisez un import. Si le module auquel vous faites référence est un module ambiant (qui utilise declare module, ou qui déclare simplement des globaux), utilisez <reference types="" />.

Certains packages n'ont pas de tslint.json, et certains tsconfig.json n'ont pas "noImplicitAny" : true, "noImplicitThis" : true, ou "strictNullChecks" : true.

Alors ils sont faux, et nous ne l'avons pas encore remarqué. Vous pouvez nous aider en soumettant une demande d'extraction pour les corriger.

Les fichiers sont-ils formatés automatiquement ?

Oui, en utilisant dprint. Nous recommandons d'utiliser une extension dprint pour votre éditeur.

Alternativement, vous pouvez activer un hook git qui formatera automatiquement votre code. Exécutez pnpm run setup-hooks. Ensuite, lorsque vous committez, la commande dprint fmt sera exécutée sur les fichiers modifiés. Si vous utilisez le clone partiel, assurez-vous d'appeler git sparse-checkout add .husky pour vérifier les hooks git avant d'exécuter le script setup-hooks.

Les pull requests n'ont pas besoin d'un formatage correct pour être fusionnées. Tout code non formaté sera automatiquement reformaté après avoir été fusionné.

💡 Si vous utilisez VS Code, nous vous suggérons de copier le fichier .vscode/settings.template.json vers .vscode/settings.json. Ce modèle définit l'extension dprint pour VS Code comme le formateur par défaut dans le dépôt.

Puis-je demander une définition ?

Voici les définitions actuellement demandées.

Qu'en est-il des définitions de type pour le DOM ?

Si les types font partie d'un standard web, ils doivent être ajoutés à TypeScript-DOM-lib-generator afin qu'ils puissent faire partie de la lib.dom.d.ts par défaut.

Qu'en est-il des définitions de type sans package correspondant ?

S'il n'y a pas de code Javascript source du tout, par exemple si vous écrivez des types d'aide ou des types pour une spécification, vous devriez publier les types vous-même, pas sur Definitely Typed. Parce qu'ils sont destinés à fournir des types pour du code Javascript existant, les packages @types ne sont pas destinés à être importés directement. En d'autres termes, vous ne devriez pas créer un package Definitely Typed destiné à être utilisé comme import type { ... } from "@types/foo". Vous ne devez pas non plus vous attendre à écrire import type { ... } from "foo" quand il n'y a pas de foo installé.

C'est différent de fournir des types pour une bibliothèque Javascript uniquement pour le navigateur ou des types pour un environnement entier comme node, bun, et al. Là, les types sont résolus soit implicitement, soit en utilisant /// <references types="foo" />.

Dois-je ajouter un espace de noms vide à un package qui n'exporte pas de module pour utiliser les importations de style ES6 ??

Certains packages, comme chai-http, exportent une fonction.

Importer ce module avec un import de style ES6 de la forme import * as foo from "foo"; conduit à l'erreur :

erreur TS2497 : Le module 'foo' se résout en une entité non-module et ne peut pas être importé en utilisant cette construction.

Cette erreur peut être supprimée en fusionnant la déclaration de la fonction avec un espace de noms vide du même nom, mais cette pratique est déconseillée. Il s'agit d'une réponse Stack Overflow couramment citée à ce sujet.

Il est plus approprié d'importer le module en utilisant la syntaxe import foo = require("foo");. Néanmoins, si vous voulez utiliser un import par défaut comme import foo from "foo"; vous avez deux options :

  • vous pouvez utiliser l'option de compilation --allowSyntheticDefaultImports si votre module d'exécution supporte un schéma d'interopérabilité pour les modules non-ECMAScript, c'est-à-dire si les importations par défaut fonctionnent dans votre environnement (par exemple Webpack, SystemJS, esm).
  • vous pouvez utiliser l'option de compilation --esModuleInterop si vous voulez que TypeScript prenne en charge l'interopérabilité non-ECMAScript (depuis TypeScript 2.7).

Un package utilise export =, mais je préfère utiliser les importations par défaut. Puis-je remplacer export = par export default ?

Comme dans la question précédente, il faut utiliser les options --allowSyntheticDefaultImports ou --esModuleInterop du compilateur.

Ne changez pas la définition du type si elle est correcte. Pour un package npm, export = est correct si node -p 'require("foo")' fonctionne pour importer un module, et export default est correct si node -p 'require("foo").default' fonctionne pour importer un module.

Je souhaite utiliser les fonctionnalités des toutes nouvelles versions de TypeScript.

Vous devrez alors ajouter un commentaire à la dernière ligne de votre en-tête de définition (après // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped): // Minimum TypeScript Version: X.Y. Ceci définira la version minimale la plus basse supportée.

Cependant, si votre projet a besoin de maintenir des types compatibles avec, disons, 3.7 et plus en même temps que des types compatibles avec 3.6 ou moins, vous devrez utiliser la fonctionnalité typesVersions. Vous trouverez une explication détaillée de cette fonctionnalité dans la documentation officielle de TypeScript.

Voici un petit exemple pour commencer :

  1. Vous devrez ajouter typesVersions au package.json :

    {
        "private": true,
        "types": "index",
        "typesVersions": {
            "<=3.6": { "*": ["ts3.6/*"] }
        }
    }
  2. Créez le sous-répertoire mentionné dans le champ typesVersions à l'intérieur de votre répertoire de types (ts3.6/ dans cet exemple). ts3.6/ supportera les versions de TypeScript 3.6 et inférieures, alors copiez-y les types et tests existants.

  3. De retour à la racine du package, ajoutez les fonctionnalités de TypeScript 3.7 que vous souhaitez utiliser. Lorsque les gens installeront le package, TypeScript 3.6 et inférieures commenceront à partir de ts3.6/index.d.ts, tandis que TypeScript 3.7 et supérieures commenceront à partir de index.d.ts.

    Vous pouvez consulter bluebird pour un exemple.

Je souhaite ajouter une API DOM qui n'est pas présente par défaut dans TypeScript.

Cela pourrait être dans TypeScript-DOM-lib-generator. Voir les lignes directrices à cet endroit. Si le standard est encore à l'état de projet, il a sa place ici. Utilisez un nom commençant par dom- et incluez un lien vers le standard comme lien "Project" dans l'en-tête. Lorsqu'il sort du mode brouillon, nous pouvons le retirer de Definitely Typed et déprécier le packageage @types associé.

Comment les versions des packages Definitely Typed sont-elles liées aux versions de la bibliothèque correspondante ?

REMARQUE : la discussion dans cette section suppose une certaine familiarité avec le Semantic versioning.

Chaque package de Definitely Typed est versionné lorsqu'il est publié sur npm. L'outil DefinitelyTyped-tools (l'outil qui publie les packages @types sur npm) définira la version du package de déclaration en utilisant le numéro de version major.minor.9999 indiqué dans package.json. Par exemple, voici les premières lignes des déclarations de type de Node pour la version 20.8.x au moment de la rédaction :

{
    "private": true,
    "name": "@types/node",
    "version": "20.8.9999"
}

Comme la version est indiquée comme 20.8.9999, la version npm du package @types/node sera également 20.8.x. Notez que la version dans package.json ne doit contenir que la version major.minor (par exemple 10.12) suivie de .9999. Cela est dû au fait que seuls les numéros de version majeure et mineure sont alignés entre les packages de bibliothèque et les packages de déclaration de type. (Le .9999 est utilisé pour s'assurer que les packages locaux @types sont toujours les plus récents pendant le développement local.) Le numéro de version patch du package de déclaration de type (par exemple .0 dans 20.8.0) est initialisé à zéro par Definitely Typed et est incrémenté chaque fois qu'un nouveau package @types/node est publié sur npm pour la même version majeure/mineure de la bibliothèque correspondante.

Parfois, les versions des packages de déclaration de type et des packages de bibliothèque peuvent être désynchronisées. Voici quelques raisons courantes pour lesquelles cela peut se produire, classées par ordre de gêne pour les utilisateurs d'une bibliothèque. Seul le dernier cas est généralement problématique.

  • Comme indiqué ci-dessus, la version patch du package de déclaration de type est indépendante de la version patch de la bibliothèque. Cela permet à Definitely Typed de mettre à jour en toute sécurité les déclarations de type pour la même version majeure/mineure d'une bibliothèque.
  • Si vous mettez à jour un package pour de nouvelles fonctionnalités, n'oubliez pas de mettre à jour le numéro de version pour qu'il corresponde à cette version de la bibliothèque. Si les utilisateurs s'assurent que les versions correspondent entre les packages JavaScript et leurs packages @types respectifs, alors npm update devrait généralement fonctionner correctement.
  • Il est courant que les mises à jour des packages de déclaration de type soient en retard par rapport aux mises à jour des bibliothèques, car ce sont souvent les utilisateurs des bibliothèques, et non les mainteneurs, qui mettent à jour Definitely Typed lorsque de nouvelles fonctionnalités de bibliothèque sont publiées. Il peut donc y avoir un décalage de quelques jours, semaines ou même mois avant qu'un membre de la communauté n'envoie une PR pour mettre à jour le package de déclaration de type pour une nouvelle version de la bibliothèque. Si cela vous impacte, vous pouvez être le changement que vous voulez voir dans le monde et être ce membre de la communauté utile !

❗ Si vous mettez à jour les déclarations de type pour une bibliothèque, définissez toujours la version major.minor dans package.json pour qu'elle corresponde à la version de la bibliothèque que vous documentez ! ❗

Si une bibliothèque est mise à jour vers une nouvelle version majeure comportant des changements importants, comment dois-je mettre à jour son package de déclarations de types ?

La gestion sémantique des versions exige que les versions avec des changements majeurs doivent incrémenter le numéro de version majeure. Par exemple, une bibliothèque qui supprime une fonction exportée publiquement après sa version 3.5.8 doit passer à la version 4.0.0 lors de sa prochaine publication. De plus, lorsque la version 4.0.0 de la bibliothèque est publiée, le package de déclarations de type Definitely Typed doit également être mis à jour à 4.0.0, y compris tous les changements majeurs de l'API de la bibliothèque.

De nombreuses bibliothèques ont une grande base d'utilisateurs (y compris les mainteneurs d'autres packages utilisant cette bibliothèque comme dépendance) qui ne passeront pas immédiatement à une nouvelle version avec des changements majeurs, car il peut s'écouler des mois avant qu'un mainteneur ait le temps de réécrire le code pour s'adapter à la nouvelle version. En attendant, les utilisateurs des anciennes versions de la bibliothèque peuvent toujours vouloir mettre à jour les déclarations de type pour les versions plus anciennes.

Si vous avez l'intention de continuer à mettre à jour les déclarations de type de l'ancienne version d'une bibliothèque, vous pouvez créer un nouveau sous-dossier (par exemple /v2/) nommé d'après la version actuelle (bientôt "ancienne") et y copier les fichiers existants de la version actuelle.

Lors de la création d'un nouveau dossier de version, assurez-vous que le champ version de package.json a été mis à jour ; pnpm résoudra automatiquement ce package versionné chaque fois que nécessaire. Si d'autres packages dans le dépôt doivent dépendre de cette nouvelle version, assurez-vous que leurs package.json soient également mis à jour.

Par exemple, si nous créons types/history/v2, son package.json ressemblerait à ceci :

{
    "private": true,
    "name": "@types/history",
    "version": "2.4.9999"
}

Un autre package peut sélectionner cette version en spécifiant :

{
    "private": true,
    "name": "@types/browser-sync",
    "version": "2.26.9999",
    "dependencies": {
        "@types/history": "^2"
    }
}

De plus, /// <reference types=".." /> ne fonctionnera pas avec le mappage de chemin, donc les dépendances doivent utiliser import.

Comment fonctionnent les changements de type majeurs si les packages de déclaration de type suivent de près la version du package de la bibliothèque ?

Les packages @types typent toujours les packages de la même version, donc @types/foo@5.4.x sont pour foo@5.4.x. En conséquence, tous les changements, qu'ils soient majeurs ou non, sont publiés en tant que révisions de correctifs, sauf s'ils sont accompagnés d'une augmentation majeure/mineure pour changer la version du package ciblé (coïncidence ou non).

En ce qui concerne les changements majeurs, les mainteneurs de DT prennent en compte la popularité du package, les avantages du changement proposé, l'effort nécessaire pour que les utilisateurs corrigent leur code, et si le changement pourrait raisonnablement être retardé jusqu'à ce qu'il puisse être synchronisé avec une augmentation majeure de la bibliothèque en amont.

Comment puis-je écrire des définitions pour des packages qui peuvent être utilisés globalement et en tant que module ?

Le manuel TypeScript contient d'excellentes informations générales sur l'écriture de définitions, ainsi que cet exemple de fichier de définition qui montre comment créer une définition en utilisant la syntaxe de module de style ES6, tout en spécifiant également les objets mis à la disposition de la portée globale. Cette technique est démontrée en pratique dans la définition de big.js, qui est une bibliothèque qui peut être chargée globalement via une balise script sur une page web, ou importée via require ou des importations de style ES6.

Pour tester comment votre définition peut être utilisée à la fois lorsqu'elle est référencée globalement ou en tant que module importé, créez un dossier test, et placez-y deux fichiers de test. Nommez l'un VotreNomBibliothèque-global.test.ts et l'autre VotreNomBibliothèque-module.test.ts. Le fichier de test global doit exercer la définition de la manière dont elle serait utilisée dans un script chargé sur une page web où la bibliothèque est disponible sur la portée globale - dans ce scénario, vous ne devez pas spécifier d'instruction d'importation. Le fichier de test module doit exercer la définition selon la façon dont elle serait utilisée lorsqu'elle est importée (y compris la ou les déclarations import). Si vous spécifiez une propriété files dans votre fichier tsconfig.json, assurez-vous d'inclure les deux fichiers de test. Un exemple pratique de ceci est aussi disponible sur la définition de big.js.

Il suffit de tester uniquement les éléments accessibles globalement dans le fichier de test global et d'exercer pleinement la définition dans le fichier de test du module, ou vice versa.

Qu'en est-il des packages scopés ?

Les types pour un package avec un scope @foo/bar doivent être placés dans types/foo__bar. Notez le double underscore.

Licence

Ce projet est placé sous la licence MIT.

Les droits d'auteur sur les fichiers de définition appartiennent à chaque contributeur mentionné au début de chaque fichier de définition.