Corriger les Unused Exports de Knip
Corriger les violations « Unused exports » de knip. Il existe plusieurs catégories de violation, chacune avec une stratégie de correction différente.
Quand l'utiliser
npm run kniprapporte « Unused exports »
Quand NE PAS l'utiliser
- L'export est consommé par du code production non-test dans un autre fichier -- quelque chose d'autre ne va pas
Workflow
1. Identifier les Violations
npm run knip
Le résultat ressemble à :
Unused exports (3)
::error file=packages/foo/src/bar.ts,line=42,title=Unused exports::myFunction
2. Classer chaque Violation
Pour chaque export signalé, grep l'ensemble du repository (pas seulement le package) :
rg "myFunction"
Déterminez dans quelle catégorie elle s'inscrit :
| Catégorie | Appelants | Correction |
|---|---|---|
| Export test-only | Utilisé dans le même fichier + fichiers de test uniquement | Extraire dans un nouveau fichier |
| Dead barrel re-export | Ré-exporté depuis index.ts, mais le code production importe via des chemins relatifs ou d'autres sous-chemins |
Supprimer le re-export du barrel |
| Export utilisé uniquement en interne | Utilisé seulement au sein du même fichier, pas par les tests ou d'autres fichiers | Supprimer le mot-clé export |
| Code mort | Aucun appelant nulle part | Supprimer l'export |
| Consommateur production existe | Utilisé par du code non-test dans un autre fichier | Pas un problème knip -- investiguer davantage |
Important : Lors du grep, excluez les fichiers de test pour identifier les consommateurs production :
rg "myFunction" --glob '!**/*.test.*'
Correction : Exports Test-Only (Extraire dans un Nouveau Fichier)
Quand une fonction est exportée uniquement pour l'accès aux tests mais est aussi utilisée en interne dans le même fichier.
Planifier l'Extraction
Avant d'écrire du code, répondez à ces questions :
a) Qu'est-ce qui se déplace vers le nouveau fichier ?
- La fonction/classe/const exportée signalée
- Toutes les fonctions helper privées dont elle dépend
- Toutes les constantes/types privés dont elle dépend
b) Certains helpers sont-ils partagés avec les fonctions qui restent ?
- Si oui, le helper doit être exporté depuis le nouveau fichier, et le fichier original l'importe
- Cela signifie que le nouveau fichier aura 2+ exports (ce qui est correct pour toute règle lint filename-match-export)
c) Le nouveau fichier aura-t-il exactement une fonction exportée ?
- Si votre projet applique une règle lint
filename-match-export, le fichier DOIT être nommé d'après cet export :myFunction.ts - Si le fichier a 2+ exports de fonction, le nom est flexible
d) Existe-t-il un fichier test avec un nom correspondant ?
- Si
bar.tsreste et quebar.test.tsexiste, le test doit toujours importer quelque chose depuis./bar(si votre projet applique une règletest-imports-source) - Si
bar.tsest supprimé (tout a été déplacé), cette règle s'applique généralement seulement quand le fichier source correspondant existe
e) Y a-t-il un risque de dépendance circulaire ?
- Dessinez le graphe d'imports : nouveau fichier -> fichier original -> nouveau fichier est circulaire
- Correction : déplacer la dépendance partagée vers le nouveau fichier ou un troisième fichier
f) Exporte-t-il une constante ?
- Si votre projet applique une règle lint
constants-file-organization, les constantes exportées doivent vivre dans un fichier nomméconstants.ts - Si la fonction extraite dépend d'une constante qu'autres fonctions du fichier original utilisent aussi, N'EXPORTEZ PAS la constante depuis le nouveau fichier. À la place, appelez la fonction (par exemple, remplacez
BUDGET[effort]pargetBudget(effort)) pour éviter d'avoir besoin d'unconstants.tsséparé
Exécuter l'Extraction
Créez le nouveau fichier dans le même répertoire :
// myFunction.ts (nouveau fichier)
import { SomeType } from '../types';
function privateHelper(): void { /* ... */ }
export function myFunction(): SomeType {
return privateHelper();
}
Mettez à jour le fichier original pour importer depuis le nouveau fichier :
// bar.ts (fichier original, mis à jour)
import { myFunction } from './myFunction';
function otherFunction() {
const result = myFunction(); // Importe maintenant depuis le nouveau fichier
}
Mettez à jour les fichiers de test pour importer depuis le nouveau fichier :
// bar.test.ts (mis à jour)
import { myFunction } from './myFunction';
// Si bar.ts existe toujours, vous pourriez avoir besoin d'importer aussi quelque chose depuis './bar'
// pour satisfaire à toute règle test-imports-source
Attention aux Violations en Chaîne
Après l'extraction, lancez npm run knip à nouveau. Si la fonction A a été extraite vers un nouveau fichier aux côtés de la fonction B que A appelle, mais B est aussi consommée seulement par les tests en externe, knip signalera aussi B. Vous devez extraire B vers son propre fichier pour que le fichier de A crée un véritable import production de B.
Exemple : supposons que throwMappedError ait d'abord été extrait aux côtés de mapResponseFailure dans error-mappers.ts. Si throwMappedError est appelée seulement en interne au sein de ce fichier (par mapResponseFailure), elle sera toujours signalée. Correction : extraire vers throwMappedError.ts, rendant l'import depuis error-mappers.ts un véritable consommateur production.
Correction : Dead Barrel Re-Exports (Supprimer depuis index.ts)
Quand un barrel index.ts ré-exporte quelque chose, mais aucun code production ne l'importe via le barrel. Cela se produit quand :
- Le code production au sein du même package utilise des imports relatifs (par exemple,
import { x } from './source') au lieu du barrel - Le code production dans d'autres packages importe directement depuis un sous-chemin (par exemple,
@scope/pkg/feature/handlers) au lieu du barrel - Le re-export a été ajouté de manière spéculative mais n'a jamais été consommé
Comment Identifier
Grep en excluant les fichiers de test. Si les seuls résultats sont :
- Le barrel
index.tslui-même - Les fichiers source utilisant des imports relatifs au sein du même package
- Les fichiers de test
Alors le re-export du barrel est inutilisé. Supprimez-le simplement depuis index.ts.
Imports de Test Entre Packages
Si un test dans un autre package importe le symbole via le barrel (par exemple, import { x } from '@scope/pkg/feature'), vous devez fournir un chemin d'import alternatif après suppression du re-export du barrel :
-
Ajoutez une subpath export dans
package.jsondu package source :{ "exports": { "./feature": "./src/feature/index.ts", "./feature/doSomething": "./src/feature/doSomething.ts" } } -
Mettez à jour le test pour importer depuis le nouveau sous-chemin :
import { doSomething } from '@scope/pkg/feature/doSomething';
Ce pattern suit les conventions de subpath-export typiques utilisées dans les monorepos.
Correction : Exports Utilisés Uniquement en Interne (Ôter l'export)
Quand un export est utilisé uniquement au sein du même fichier et n'est importé par rien d'autre (pas même par les tests), supprimez simplement le mot-clé export :
// Avant
export const MySchema = z.object({ ... });
// Après
const MySchema = z.object({ ... });
C'est courant pour les schémas Zod qui sont seulement utilisés comme blocs de construction pour d'autres schémas du même fichier.
Vérifier
Exécutez TOUS ces contrôles sur les packages affectés :
# Knip passe (c'est le point de la manœuvre)
npm run knip
# Les types compilent toujours
npm run typecheck
# Les tests passent toujours
npm run test
# Le lint passe (détecte filename-match-export, test-imports-source, constants-file-organization, etc.)
npm run lint
S'il existe des imports entre packages, vérifiez aussi le package consommateur.
Règles Lint en Interaction
De nombreux monorepos TypeScript superposent des règles lint personnalisées supplémentaires par-dessus knip. Adaptez les corrections ci-dessous à celles que votre projet utilise.
filename-match-export (ou similaire)
Si un fichier a exactement UNE fonction exportée (pas un composant React), le nom du fichier doit correspondre au nom de la fonction.
export function loadConfigdansloadConfig.ts-- réussitexport function loadConfigdanshelpers.ts-- échoue- Deux exports dans
helpers.ts-- la règle ne s'applique pas (exports multiples)
test-imports-source (ou similaire)
Si foo.test.ts et foo.ts existent tous les deux, le test doit importer depuis ./foo.
- Les imports comme
import { x } from './foo'satisfont la règle - Accepte généralement aussi d'importer depuis
'.'ou'./index'siindex.tsré-exporte depuisfoo.ts - Si
foo.tsest supprimé, la règle ne s'applique pas
constants-file-organization (ou similaire)
Les constantes exportées doivent être définies dans un fichier nommé constants.ts.
- Si vous extrayez une fonction qui dépend d'une constante partagée, N'EXPORTEZ PAS la constante depuis le fichier de la fonction
- À la place, remplacez l'accès direct à la constante par des appels de fonction (par exemple,
BUDGET[effort]devientgetBudget(effort)) - Ou déplacez la constante vers un fichier
constants.ts
Comment Knip Trace les Exports
- Knip ignore les fichiers de test (
**/*.test.*,**/*.spec.*) ignoreIssuesdansknip.jsonsupprime les avertissements SUR le fichier listé, mais NE REND PAS l'export source « utilisé »- Les ré-exports de barrel (
export { x } from './source') depuis unindex.tsavecignoreIssuesne comptent PAS comme une utilisation de l'export source - Seuls les imports authentiques depuis des fichiers project non-test, non-ignorés comptent comme une utilisation
includeEntryExports: true(si défini) signifie que les exports depuis les fichiers entry point sont aussi vérifiés, donc les fichiers de style entry-point (migrations, scripts) pourraient avoir besoin d'unignoreIssuesexplicite
Package Subpath Exports
Quand vous supprimez des ré-exports de barrel sur lesquels des tests cross-package s'appuyaient, ajoutez des subpath exports à package.json :
{
"exports": {
"./feature": "./src/feature/index.ts",
"./feature/doSomething": "./src/feature/doSomething.ts"
}
}
Quoi Ne Pas Faire
- N'ajoutez pas de fichiers à
ignoreIssuesdansknip.jsonà moins qu'ils ne soient de véritables scripts entry point (migrations, CLIs) - Ne fusionnez pas toutes les fonctions dans un seul fichier pour réduire les exports -- l'utilisation au sein du même fichier d'un export ne compte pas comme utilisation du point de vue de knip
- Ne supprimez pas le mot-clé
exportsi les tests en ont besoin -- les tests se casseraient - Ne créez pas d'imports circulaires entre le nouveau et le fichier original
- N'exportez pas de constantes depuis des fichiers autres que
constants.tssi votre projet applique une règle lintconstants-file-organization