Tslint: Conflit entre les règles 'no-inferrable-types' et 'typedef'

Créé le 3 oct. 2015  ·  33Commentaires  ·  Source: palantir/tslint

Re-bonjour,

Je ne sais pas s'il s'agit d'un problème ou d'une décision de conception, mais je peux voir un conflit entre les règles no-inferrebale-types et typedef .

Ex.

function fn(): void {
    for (let i = 0; i < 100; i++) {
        console.log(i);
    }
}

Extrait de https://github.com/palantir/tslint/blob/master/docs/sample.tslint.json :

 "typedef": [true, ...],
 "no-inferrable-types": true,

Lorsque j'ai ces deux règles activées, j'obtiens:

error (typedef) test.ts[2, 12]: expected variable-declaration: 'i' to have a typedef

L'ajout de l'annotation de type number à la variable i provoque à son tour l'erreur suivante :

error (no-inferrable-types) test.ts[2, 14]: LHS type (number) inferred by RHS expression, remove type annotation

Est-il possible de faire coexister ces deux règles ?

Par exemple, je veux avoir des variables déductibles directement déclarées avec un type primitif (comme le dit la règle doc: number , boolean ou string ), mais d'un autre côté, je veux pour forcer les typedefs sur les types non primitifs.

Merci,

O.

P1 Enhancement 🌹 R.I.P. 🌹

Commentaire le plus utile

:+1: Idéalement (imo), je voudrais un moyen de dire "toujours besoin d'un typedef, à moins que le type ne soit déductible". Ce que je ne pense pas possible pour le moment.

Tous les 33 commentaires

Bonne prise, merci pour le heads-up. J'ai ajouté la règle no-inferrable-types sans penser à la façon dont elle pourrait entrer en conflit avec la règle typedef , oups ! Pour l'instant, je recommanderais de désactiver l'un des deux ou d'utiliser uniquement certaines options de la règle typedef .

À plus long terme, je pense que nous voudrons soit intégrer no-inferrable-types dans la règle typedef , soit que nous voudrons au moins que TSLint détecte les configurations conflictuelles, comme si les deux règles étaient activées.

Je suis confronté au même problème.
J'ai désactivé les types non inférables pour l'instant.

Oui pareil ici, j'aimerais avoir la possibilité de faire coexister les deux règles.
Je ne voudrais pas que la règle typedef entre en jeu si le type de la variable peut être déduit.
c'est-à-dire que "no-inferrable-types" devrait avoir la priorité sur "typedef"

+1

let id: number = 0;
for (let job: string of NAMES_PROFFESSIONS) {
     /** some code */
     id++;
}

(types non déductibles) Type LHS (nombre) déduit par l'expression RHS, supprimer l'annotation de type

+1

Votre définition des types "inférables" inclut-elle les affectations de constructeur ?

// BAD (this hurts my eyes to read)
let labels: Map<string, string> = new Map<string, string>();
// GOOD (type is obvious)
let labels = new Map<string, string>();

mais aussi...

// BAD (in a diff, it's not obvious what this type is)
let labels = this.buildLabels();
// GOOD
let labels: Map<string, string> = this.buildLabels();

Oui, c'est dangereux. Si je veux simplifier mon code et empêcher d'utiliser la déclaration de type pour les variables directement initialisées, je ne peux pas le faire strictement et cela amène à une telle chose:

let x = 2;
let y;
let z: number;

x = 1;
y = 1;
z = 1;
x = 's'; // Type 'string' is not assignable to type 'number'
y = 's'; // It's OK
z = 's'; // Type 'string' is not assignable to type 'number'

Cela peut être une option très utile pour autoriser la déclaration de type de saut uniquement pour les variables initialisées.

… et vraiment pas que pour les types primitifs, comme le dit @pgonzal !
Regardez ça, c'est terrible :

const onChange: () => void = () => this.update();

:+1: Idéalement (imo), je voudrais un moyen de dire "toujours besoin d'un typedef, à moins que le type ne soit déductible". Ce que je ne pense pas possible pour le moment.

J'ai rencontré cela et j'ai créé un indicateur ignore-params qui m'aide dans mon cas. Je veux forcer les typedefs pour tous les paramètres de méthode/fonction même lorsqu'ils peuvent être facilement déduits.

Voir PR: # 1190 si vous voulez l'essayer

Cela fait un moment que le problème initial n'a pas été soumis. L'option recommandée à ce stade est-elle de désactiver no-inferrable-types et d'inclure le type sur tout ? Toute autre chose à essayer d'activer et de combiner à la fois no-inferrable-types et typedef semble être un hack et entraîne un tas d'avertissements inutiles. En espérant une meilleure solution prochainement.

@corydeppen Notez les 8 pouces vers le haut sur la suggestion de @englercj , ci-dessus. On ne sait pas ce que "combiner" signifie dans votre commentaire "semble être un hack". Si vous voulez dire "utiliser ensemble dans tslint.json , alors, oui. Mais "combiner" un argument optional-inferrable-types sur typedef serait génial (au moins, pour 9 d'entre nous).

Pouvons-nous avoir une mise à jour à ce sujet, s'il vous plaît ?

Je pense que la meilleure façon de gérer cela est de déprécier le no-inferrable-types et de simplement passer un objet d'option à typedef pour ignorer le manque de définitions de type si le type est déductible selon certains modèles, comme initialized , initialized primitives , call signatures et d'autres modèles qui répondraient à nos besoins en tant que développeurs.

Pour moi, cela a plus de sens, car il devrait toujours y avoir un typedef, à moins que quelque chose ne vous dise quel est le type de la fonction. Et il serait également configurable, car nous voulons peut-être que le properties initialisé dans une classe ait un type inférable, mais pas pour le call signatures par exemple.

Ce serait formidable si quelqu'un pouvait intervenir pour résoudre ce problème. Jusque-là, nous sommes obligés de choisir entre "pas assez de déclarations de type pour être lisibles" ou "encombré de trop de déclarations de type".

Ce problème est ouvert depuis le 3 octobre 2015 - depuis lors, mon équipe a créé environ 2000 fichiers source TypeScript qui sont tous encombrés de trop de déclarations de type.

Le typedef accepte une configuration. Alors peut-être juste une autre configuration juste pour ignorer la définition de type si le type est déductible, ce qui signifie

Tapez simplement où n'est pas initialisé.

Il semble que parce qu'il n'y a pas de consensus clair sur la façon de traiter la question, aucun progrès n'est réalisé. Exemple de commentaire : https://github.com/theia-ide/theia/issues/356#issuecomment -319350833

Je soupçonne que nous sommes tous d'accord pour dire que n'importe quelle solution vaut mieux que de laisser les choses telles quelles. Si vous pensez que tout changement au statu quo concernant ce problème est bon, veuillez 👍 ce commentaire. Si vous êtes suffisamment informé pour créer un PR pour résoudre ce problème, veuillez nous aider tous ❤️ .

Accepterait un PR pour :

  • ajouter une option à typedef qui lui permet d'ignorer les cas où no-inferrable-types dit de ne pas fournir de type

Le typedef accepte une configuration. Alors peut-être juste une autre configuration juste pour ignorer la définition de type si le type est inférable, ce qui signifie 'Tapez simplement là où n'est pas initialisé.'

La règle typedef est destinée aux personnes qui aiment avoir des définitions de type explicites dans leur base de code. Si vous souhaitez que le comportement ci-dessus "tape simplement là où n'est pas initialisé", vous feriez mieux de désactiver typedef et de vous assurer que noImplictAny est activé en tant qu'option de compilateur TypeScript.

Il y a aussi le cas délicat où certaines choses qui sont initialisées ont de toute façon besoin d'un typedef, comme dans l'extrait suivant :

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

De plus, pendant que nous corrigeons ce problème, je voulais mentionner qu'il existe probablement d'excellentes règles tierces, comme no-unnecessary-type-annotation (https://github.com/ajafff/tslint-consistent-codestyle/blob/ master/docs/no-unnecessary-type-annotation.md) par exemple. Si quelqu'un connaît d'autres règles tierces qui donnent le comportement souhaité, veuillez les publier ici et nous pourrons les recommander officiellement ou les adopter dans le noyau si cela a du sens.

@JKillian merci pour la recommandation, je pense que c'est en fait ce que je voulais. Il y a un très bon article sur le fait d'éviter le type any : n'utilisez pas "nu", créez plutôt une "interface quelconque".

Sur:

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

Je ne vois pas en quoi cela pourrait être un comportement indésirable ou un cas délicat. Vous voulez vous assurer que obj a une propriété field avec la valeur value , et même lorsque vous initialisez literal0 avec une propriété qui ressemble aux contraintes , vous pouvez modifier cela en une autre chaîne.

Je sais que ce n'est pas un bon cas d'utilisation, mais la plupart des cas où vous utilisez un littéral, vous voulez probablement ce littéral, pas un primitif.

J'ai la configuration suivante :
json "no-inferrable-types": true, "typedef": [true, "call-signature", "parameter"],
Et ce code :
javascript private static readonly DEVICE_UID: string = 'device_uid'; private static readonly DEVICE_PLATFORM: string = 'browser'; private static readonly AGENT_DEFAULT_ICON = 'http://localhost:3000/icon.png';

Pourquoi je n'obtiens pas d'erreur dans les deux premières déclarations ?

@sandrocsimas Intéressant, mais hors sujet je pense ; AFAICT ce problème n'est pas lié à ce problème. Je vous suggère de commencer un autre numéro (fwiw!).

@estaub , oui je le ferai. J'obtiens le même comportement même sans la règle typedef.

@sandrocsimas c'est parce qu'il s'agit d'une propriété en lecture seule, et un tel Typescript déduit son type en tant que littéral. En le tapant comme une chaîne, vous dites qu'il devrait avoir une chaîne, il n'aura pas nécessairement cette valeur littérale et la valeur ne devrait pas changer de manière statique.

Ce serait bien d'avoir une règle "require-typedef-except-inferrable".

@FiretronP75 comme l'a dit @JKillian , c'est juste l'option noImplicitAny du TSC.

@michaeljota merci, je n'avais pas réalisé que l'option noImplicitAny du compilateur donne des exceptions pour inférable. Ce serait toujours bien d'avoir tslint cependant, pour l'option d'en faire un avertissement au lieu de casser la compilation, et pour avoir les drapeaux de commentaire tslint.

Je vois pourquoi ce serait quelque chose de recherché, mais avec no-unused-variables comme exemple, je ne pense pas que les cas d'utilisation couverts par le TSC seront pris en charge par l'équipe TSLint. Je sais que ce n'est pas la même _erreur de linter_ qu'une _erreur de compilateur_ mais à la fin, ils concernent tous les deux un meilleur code écrit. Aujourd'hui, avec des solutions comme Webpack ou Parcel qui vous permettent de compiler et d'exécuter le code même avec des erreurs TSC, je ne vois pas cela comme un vrai problème.

Cela a-t-il été corrigé dans la dernière version ?

Je ne pense toujours pas que ce soit sur la feuille de route. Vous devriez envisager d'utiliser noImplicitAny du TSC

☠️ L'heure de TSLint a sonné ! ☠️

TSLint n'accepte plus la plupart des demandes de fonctionnalités par #4534. Voir typescript-eslint.io pour la nouvelle façon brillante de pelucher votre code TypeScript avec ESLint . ✨

Ce fut un plaisir d'ouvrir le sourcing avec vous tous !

🤖 Bip boop ! 👉 TSLint est obsolète 👈 _(#4534)_ et vous devriez passer à typescript-eslint ! 🤖

🔒 Ce problème est verrouillé pour éviter d'autres discussions inutiles. Merci! 👋

Cette page vous a été utile?
0 / 5 - 0 notes