Tslint: Die Regeln „no-inferrable-types“ und „typedef“ stehen in Konflikt

Erstellt am 3. Okt. 2015  ·  33Kommentare  ·  Quelle: palantir/tslint

Hallo nochmal,

Ich bin mir nicht sicher, ob dies ein Problem oder eine Designentscheidung ist, aber ich sehe einen Konflikt zwischen den Regeln no-inferrebale-types und typedef .

Ex.

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

Ausschnitt von https://github.com/palantir/tslint/blob/master/docs/sample.tslint.json :

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

Wenn ich diese beiden Regeln aktiviert habe, bekomme ich:

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

Das Hinzufügen der Typanmerkung number zur Variablen i verursacht wiederum den folgenden Fehler:

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

Gibt es eine Möglichkeit, diese beiden Regeln nebeneinander zu haben?

Zum Beispiel möchte ich ableitende Variablen direkt mit primitivem Typ deklarieren (wie im Regeldokument steht: number , boolean oder string ), aber auf der anderen Seite möchte ich Typedefs für nicht-primitive Typen zu erzwingen.

Danke,

Ö.

P1 Enhancement 🌹 R.I.P. 🌹

Hilfreichster Kommentar

:+1: Idealerweise (imo) würde ich gerne sagen "immer eine Typedef erforderlich, es sei denn, der Typ ist ableitbar". Was ich im Moment nicht für möglich halte.

Alle 33 Kommentare

Guter Fang, danke für den Hinweis. Ich habe die no-inferrable-types -Regel hinzugefügt, ohne darüber nachzudenken, wie sie mit der typedef -Regel in Konflikt geraten könnte, hoppla! Im Moment würde ich empfehlen, eines der beiden auszuschalten oder nur einige Optionen der typedef -Regel zu verwenden.

Längerfristig sollten wir entweder no-inferrable-types in die typedef -Regel integrieren oder TSLint zumindest widersprüchliche Konfigurationen erkennen lassen, z. B. wenn beide Regeln aktiviert sind.

Ich stehe vor dem gleichen Problem.
Ich habe No-Inferrable-Typen vorerst deaktiviert.

Ja, auch hier, ich hätte gerne die Möglichkeit, beide Regeln nebeneinander existieren zu lassen.
Ich möchte nicht, dass die Typedef-Regel eintritt, wenn der Typ der Variablen abgeleitet werden kann.
dh "no-inferrable-types" sollte Vorrang vor "typedef" haben

+1

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

(no-inferrable-types) LHS-Typ (Zahl) abgeleitet durch RHS-Ausdruck, Typanmerkung entfernen

+1

Beinhaltet Ihre Definition von "ableitbaren" Typen Konstruktorzuweisungen?

// 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>();

aber auch...

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

Ja, es ist gefährlich. Wenn ich meinen Code vereinfachen und verhindern möchte, dass Typdeklarationen für direkt initialisierte Variablen verwendet werden, kann ich dies nicht strikt tun, und dies führt zu so etwas:

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'

Es kann eine sehr nützliche Option sein, die Typdeklaration nur für initialisierte Variablen zuzulassen.

… und wirklich nicht nur für primitive Typen, wie @pgonzal sagt!
Schau dir das an, es ist schrecklich:

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

:+1: Idealerweise (imo) würde ich gerne sagen "immer eine Typedef erforderlich, es sei denn, der Typ ist ableitbar". Was ich im Moment nicht für möglich halte.

Ich bin darauf gestoßen und habe ein ignore-params -Flag erstellt, das in meinem Fall hilft. Ich möchte Typedefs für alle Methoden-/Funktionsparameter erzwingen, auch wenn sie leicht abgeleitet werden können.

Siehe PR: #1190, wenn Sie es ausprobieren möchten

Es ist schon eine Weile her, dass die ursprüngliche Ausgabe eingereicht wurde. Ist die empfohlene Option an dieser Stelle, no-inferrable-types zu deaktivieren und den Typ für alles einzuschließen? Alles andere zu versuchen und zu aktivieren und sowohl no-inferrable-types als auch typedef zu kombinieren, scheint ein Hack zu sein und führt zu einer Reihe sinnloser Warnungen. Hoffe auf eine bessere Lösung in naher Zukunft.

@corydeppen Beachten Sie die 8 Daumen hoch für den Vorschlag von @englercj oben. Es ist unklar, was "kombinieren" in Ihrem Kommentar "scheint wie ein Hack" bedeutet. Wenn Sie "zusammen in tslint.json verwenden" meinen, dann ja. Aber das "Kombinieren" eines optional-inferrable-types Arguments auf typedef wäre großartig (zumindest für 9 von uns).

Können wir dazu bitte ein Update bekommen?

Ich denke, der beste Weg, dies zu handhaben, besteht darin, no-inferrable-types abzulehnen und einfach ein Optionsobjekt an typedef zu übergeben, um das Fehlen von Typdefinitionen zu ignorieren, wenn der Typ gemäß bestimmten Mustern als initialized ableitbar ist initialized primitives , call signatures und andere Muster, die unsere Anforderungen als Entwickler erfüllen würden.

Für mich macht das mehr Sinn, denn es sollte immer eine Typedef geben, es sei denn, es gibt etwas, das Ihnen sagt, um welchen Typ es sich bei der Funktion handelt. Und es wäre auch konfigurierbar, denn vielleicht möchten wir, dass das initialisierte properties in einer Klasse einen ableitbaren Typ hat, aber beispielsweise nicht für das call signatures .

Es wäre toll, wenn jemand einspringen könnte, um das zu beheben. Bis dahin sind wir gezwungen, zwischen „nicht genügend Typdeklarationen, um lesbar zu sein“ und „überladen mit zu vielen Typdeklarationen“ zu wählen.

Dieses Problem ist seit dem 3. Oktober 2015 offen – seitdem hat mein Team etwa 2000 TypeScript-Quelldateien erstellt, die alle mit zu vielen Typdeklarationen überladen sind.

Das typedef akzeptiert eine Konfiguration. Also vielleicht nur eine andere Konfiguration, nur um die Typdefinition zu ignorieren, wenn der Typ ableitbar ist, was bedeutet

Geben Sie einfach dort ein, wo nicht initialisiert wird.

Es sieht so aus, als würden keine Fortschritte erzielt, weil es keinen klaren Konsens darüber gibt, wie mit dem Problem umgegangen werden soll. Beispielkommentar: https://github.com/theia-ide/theia/issues/356#issuecomment -319350833

Ich vermute, wir sind uns alle einig, dass jede Lösung besser ist, als die Dinge so zu lassen, wie sie sind. Wenn Sie denken, dass eine Änderung des Status quo in Bezug auf dieses Problem gut ist, 👍 bitte diesen Kommentar. Wenn Sie sachkundig genug sind, um eine PR zur Behebung dieses Problems zu erstellen, helfen Sie uns allen bitte dabei ❤️ .

Würde eine PR annehmen an:

  • füge eine Option zu typedef hinzu, die es Fälle ignorieren lässt, in denen no-inferrable-types sagt, dass kein Typ angegeben werden soll

Die Typedef akzeptiert eine Konfiguration. Also vielleicht nur eine andere Konfiguration, um die Typdefinition einfach zu ignorieren, wenn der Typ ableitbar ist, was bedeutet: "Einfach eingeben, wo nicht initialisiert wird."

Die typedef -Regel ist für Leute, die gerne explizite Typdefinitionen in ihrer Codebasis haben. Wenn Sie möchten, dass das obige Verhalten "einfach dort eingibt, wo nicht initialisiert wird", sollten Sie typedef besser deaktivieren und sicherstellen, dass noImplictAny als TypeScript-Compileroption aktiviert ist.

Es gibt auch den kniffligen Fall, dass einige Dinge, die initialisiert werden, sowieso eine Typedef benötigen, wie im folgenden Schnipsel:

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);

Auch wenn wir das behoben haben, wollte ich erwähnen, dass es wahrscheinlich einige großartige Regeln von Drittanbietern gibt, wie no-unnecessary-type-annotation (https://github.com/ajafff/tslint-consistent-codestyle/blob/ master/docs/no-unnecessary-type-annotation.md) zum Beispiel. Wenn jemand andere Regeln von Drittanbietern kennt, die das gewünschte Verhalten liefern, posten Sie sie bitte hier und wir können sie offiziell empfehlen oder sie in den Kern übernehmen, wenn es sinnvoll ist.

@JKillian danke für die Empfehlung, ich glaube das wollte ich eigentlich. Es gibt einen sehr guten Beitrag zur Vermeidung any -Typ: Verwenden Sie nicht "naked any", erstellen Sie stattdessen ein "any interface".

Etwa:

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);

Ich sehe nicht, wie dies ein unerwünschtes Verhalten oder ein kniffliger Fall sein könnte. Sie möchten sicherstellen, dass obj eine Eigenschaft field mit dem Wert value hat, und selbst wenn Sie literal0 mit einer Eigenschaft initialisieren, die wie die Einschränkungen aussieht , Sie könnten das in eine andere Zeichenfolge ändern.

Ich weiß, dass dies kein guter Anwendungsfall ist, aber in den meisten Fällen, in denen Sie ein Literal verwenden, möchten Sie wahrscheinlich dieses Literal und kein Primitiv.

Ich habe folgende Konfiguration:
json "no-inferrable-types": true, "typedef": [true, "call-signature", "parameter"],
Und dieser 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';

Warum erhalte ich in den beiden ersten Deklarationen keinen Fehler?

@sandrocsimas Interessant, aber nicht zum Thema, denke ich; AFAICT, dass das Problem nichts mit diesem Problem zu tun hat. Ich würde vorschlagen, dass Sie ein anderes Problem beginnen (fwiw!).

@estaub , ja das werde ich. Ich bekomme das gleiche Verhalten auch ohne die Typedef-Regel.

@sandrocsimas das liegt daran, dass es sich um eine schreibgeschützte Eigenschaft handelt und solche Typoskripte ihren Typ als Literal ableiten. Wenn Sie es als Zeichenfolge eingeben, sagen Sie, dass es eine Zeichenfolge haben sollte, es muss nicht unbedingt diesen Literalwert haben und der Wert sollte sich nicht statisch ändern.

Es wäre schön, eine 'require-typedef-außer-inferrable'-Regel zu haben.

@FiretronP75 wie @JKillian sagte, das ist nur noImplicitAny Option des TSC.

@michaeljota danke, ich wusste nicht, dass die Option noImplicitAny des Compilers Ausnahmen für schlussfolgerbar gibt. Es wäre jedoch immer noch schön, tslint zu haben, um die Möglichkeit zu haben, es zu einer Warnung zu machen, anstatt die Kompilierung abzubrechen, und um die tslint-Kommentar-Flags zu haben.

Ich verstehe, warum dies etwas sein sollte, aber mit no-unused-variables als Beispiel glaube ich nicht, dass Anwendungsfälle, die vom TSC abgedeckt werden, vom TSLint-Team unterstützt werden. Ich weiß, dass ein _Linter-Fehler_ nicht dasselbe ist wie ein _Compiler-Fehler_, aber am Ende geht es bei beiden darum, besseren Code zu schreiben. Heutzutage mit Lösungen wie Webpack oder Parcel, mit denen Sie den Code auch mit TSC-Fehlern kompilieren und ausführen können, sehe ich dies nicht als wirkliches Problem an.

Wurde das in der neusten Version behoben?

Ich glaube immer noch nicht, dass das auf der Roadmap steht. Sie sollten erwägen, noImplicitAny aus dem TSC zu verwenden

☠️ TSLints Zeit ist gekommen! ☠️

TSLint akzeptiert die meisten Funktionsanfragen per #4534 nicht mehr. Siehe typescript-eslint.io für die neue, glänzende Möglichkeit, Ihren TypeScript-Code mit ESLint zu linten. ✨

Es war ein Vergnügen, Open Sourcing mit euch allen zu machen!

🤖 Piep boop! 👉 TSLint ist veraltet 👈 _(#4534)_ und Sie sollten zu typescript-eslint wechseln ! 🤖

🔒 Dieses Thema wird gesperrt, um weitere unnötige Diskussionen zu verhindern. Danke schön! 👋

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

dashmug picture dashmug  ·  3Kommentare

ghost picture ghost  ·  3Kommentare

jacob-robertson picture jacob-robertson  ·  3Kommentare

avanderhoorn picture avanderhoorn  ·  3Kommentare

DanielKucal picture DanielKucal  ·  3Kommentare