Typescript: Doppelte Typdeklarationen mit npm-Link

Erstellt am 15. Jan. 2016  ·  147Kommentare  ·  Quelle: microsoft/TypeScript

Verwenden von TypeScript 1.7.3.

Angenommen, ich habe die folgenden npm-Pakete.
Die Deklarationsdateien werden vom TypeScript-Compiler generiert und aus den anderen Paketen auf die hier beschriebene Weise

Paket-a

ts src:

export default class ClassA {
  private foo: string;
  bar: number;
}

ts Erklärung:

declare class ClassA {
  private foo;
  bar: number;
}
export default ClassA;

Paket-b (hängt von Paket-a ab):

ts src:

import ClassA from 'package-a';

namespace ClassAFactory {
  export function create(): ClassA {
    return new ClassA();
  }
}
export default ClassAFactory;

ts Erklärung:

import ClassA from 'package-a';

declare namespace ClassAFactory {
  function create(): ClassA;
}
export default ClassAFactory;

Paket-c (hängt von Paket-a und Paket-b ab):

ts src:

import ClassA from 'package-a';
import ClassAFactory from 'package-b';

let classA: ClassA;
classA = ClassAFactory.create(); // error!!

Die letzte Zeile verursacht einen Fehler beim Kompilieren:

error TS2322: Type 'ClassA' is not assignable to type 'ClassA'.
Types have separate declarations of a private property 'foo'.

Wenn ich die Zeile private foo; aus der Deklaration von Paket-a entferne, gibt TypeScript keinen Fehler aus.
Diese Problemumgehung ist jedoch etwas schmerzhaft.

Ich verstehe, dass es beabsichtigt ist, private Eigenschaften einer Deklaration auszusetzen (https://github.com/Microsoft/TypeScript/issues/1532).
Ich denke, TypeScript sollte private Eigenschaften beim Kompilieren der Variablenzuweisung ignorieren.
Oder gibt es dafür eine bessere Lösung?

@types Bug Fixed

Hilfreichster Kommentar

Ich habe gerade eine Änderung zusammengeführt, die versucht, doppelte Pakete anhand ihres Namens und ihrer Version zu erkennen und nur eines zu verwenden. Bitte probieren Sie es mit typescript@next wenn dies das nächste Mal veröffentlicht wird.

Alle 147 Kommentare

Es gibt hier nur eine Root-Deklaration von ClassA , daher sollte dieser Fehler nicht auftreten.

Tut mir leid, dass ich festgestellt habe, dass dies mit npm link .

Wenn ich npm link , werden Pakete wie folgt installiert, da einfach symbolische Links erstellt werden.

package-c
|
-- node_modules
    |
    -- package-a
    |   |
    |   -- index.d.ts
    |   |
    |   ...
    |
    -- package-b
        |
        -- index.d.ts
        |
        -- node_modules
        |   |
        |   -- package-a
        |       |
        |       -- index.d.ts
        |       |
        |       ...
        |
        ...

Wie gezeigt, gibt es anscheinend zwei verschiedene Deklarationsdateien für Paket-a.
Wenn ich Pakete normalerweise mit npm install installiere, geschieht dies nicht, da die Deklaration von Paket-a in diesem Fall nicht in Paket-b enthalten ist.

Ich hoffe, dass es dafür sowieso eine Lösung gibt, aber es könnte schwierig sein und eine niedrige Priorität haben.

Am Ende habe ich npm link , und das ist für mich nicht mehr wichtig.

Fair genug, aber jemand anderes könnte: zwinker:

Es gibt tatsächlich zwei Dateien auf der Festplatte mit zwei Deklarationen von ClassA. Der Fehler ist also korrekt. Beim Vergleich dieser Typen müssen jedoch Knotenmodule berücksichtigt werden. Dieses Problem wurde bereits unter https://github.com/Microsoft/TypeScript/issues/4800 gemeldet. Für Enums haben wir die Regel in eine halbnominale Prüfung geändert. Möglicherweise machen Sie dasselbe für Klassen.

+1 dazu mit TS 1.7.5 mit allen relevanten Paketen NPM-verknüpft. Ich habe versucht, einen Testfall zu erstellen, der das Problem aufweist, konnte es aber nicht. Unabhängig davon, was ich versucht habe, war TS mit dem Szenario, das mit TS2345 in meiner Anwendung fehlschlägt, in Ordnung, und soweit ich das beurteilen konnte, waren alle Kopien der problematischen .d.ts-Datei Symlinks zu derselben Datei, daher sollte dies nicht der Fall sein haben unterschiedliche Erklärungen innerhalb des Typs. Es wäre jedoch schön, wenn der von Typescript ausgegebene Fehler auf die Dateien verweisen würde, die die beiden inkompatiblen Typen deklarieren, da dies möglicherweise Licht auf etwas werfen könnte, das ich nicht in Betracht ziehe. Im Moment heißt es, dass es zwei Definitionen gibt, aber nichts hilft dem Entwickler, das Problem zu lokalisieren.

Um dieses Problem zu umgehen, können Sie <any> für den widersprüchlichen Ausdruck verwenden, um die Typprüfung zu überspringen. Offensichtlich müssen Sie möglicherweise eine andere Typanmerkung ausführen, die Sie zuvor möglicherweise nicht mussten. Ich hoffe, jemand kann dieses Problem irgendwann eingrenzen.

BEARBEITEN: machte deutlich, dass in meinem Fall NPM-Link im Spiel ist

Noticed TS 1.8 ist verfügbar, aktualisiert und das Problem besteht auch in dieser Version weiterhin.

Vielen Dank für die Arbeit bei der Analyse und Dokumentation dieses Problems. Wir haben das gleiche Problem in einigen unserer Codebasen. Wir haben einige Projekte portiert, um package.json Abhängigkeiten richtig zu verwenden, aber jetzt sehen wir dies, wenn wir npm link während der Entwicklung verwenden.

Kann ich Ihnen bei der Lösung dieses Problems helfen?

Ich verwende Lerna, das Pakete mit Symlinks verknüpft, und sehe das Problem auch dort. Typoskript Version 2.0.3.

Leider sind Lerna und seine Symlinks eine schwierige Anforderung, daher habe ich diese unangenehme Problemumgehung verwendet, um eine gute Kompilierung zu erreichen, während sie von den Verbrauchern weiterhin ordnungsgemäß typüberprüfbar ist:

export class MyClass {
  constructor(foo: Foo) {
    (this as any)._foo = foo;
  }

  get foo() {
    return (this as any)._foo as Foo;
  }
}

Die Klasse ist sehr klein, daher war es nicht so anstrengend, und ich erwarte nicht, dass sich dies jemals wirklich ändert. Deshalb halte ich dies für eine akzeptable Problemumgehung.

Zu Ihrer Information, ich bin auch hier gelandet, weil ich npm link und diesen Fehler erhalten habe. Hat jemand eine Problemumgehung dafür gefunden?

@xogeny Können Sie

@mhegazy Nun, ich habe angefangen, diese Fehler wie oben zu bekommen (außer ich habe Observable von rxjs , dh "Typ 'Observable' kann nicht dem Typ 'Observable' zugewiesen werden). Natürlich schien es seltsam, weil die beiden, auf die ich in beiden Modulen Observable aus genau der gleichen Version von rxjs verwies. Aber wo sich die Typen "trafen", bekam ich einen Fehler. Ich habe mich umgesehen und Schließlich fand ich dieses Problem, bei dem npm link dieser Fehler auftritt . Ich habe wie andere das rxjs verweisen).

Beantwortet das deine Frage? Ich frage, weil ich nicht denke, dass mein Fall anders aussieht als die anderen hier, also bin ich mir nicht sicher, ob dies Ihnen hilft.

Wir haben in TS2.0 speziell daran gearbeitet, npm link -Szenarien zu aktivieren (siehe https://github.com/Microsoft/TypeScript/pull/8486 und # 8346). Haben Sie ein Beispiel, in dem ich sehen kann, wo der npm-Link für Sie immer noch nicht funktioniert?

Huh. Ich verwende 2.0.3 (ich habe es überprüft). Ich werde versuchen, einen reproduzierbaren Fall zu erstellen.

Übrigens sollten Sie diese Threads weiterverfolgen, da sie implizieren, dass dies ab TS 2.0 immer noch ein Problem ist:

https://github.com/ReactiveX/rxjs/issues/1858
https://github.com/ReactiveX/rxjs/issues/1744

Das Problem, das ich in meinem Lerna-Repo sehe, ist etwas kompliziert, daher habe ich unter https://github.com/seansfkelley/typescript-lerna-webpack-sadness eine abgespeckte Version davon erstellt https://github.com/TypeStrong/ts-loader/issues/324 abgelegt.

Ich verwende Typoskript 2.0.3 und sehe diesen Fehler mit Observable wie oben beschrieben, z

Type 'Observable<Location[]>' is not assignable to type 'Observable<Location[]>'. Property 
            'source' is protected but type 'Observable<T>' is not a class derived from 'Observable<T>'.

Ich treffe dies auch in einem Lerna Monorepo-Paket. Es scheint, als würden die meisten, aber nicht alle Teile des Typsystems den Realpath verwenden, um Dateien eindeutig zu identifizieren. Wenn Sie den Zweig entlang fahren, der den Symlink-Pfad anstelle des Realpfads verwendet, erhalten Sie identische, aber unterschiedliche Typen.

Dies ist ein ziemlich brutales Problem, das nur komplexere Codebasen betrifft, und es scheint unmöglich zu sein, es zu umgehen, ohne drastische Maßnahmen zu ergreifen. Ich hoffe, ich kann Sie alle davon überzeugen, ihm die Aufmerksamkeit zu schenken, die es verdient. 😄

Dies ist am auffälligsten in Fällen, in denen Sie eine App haben, die von Abhängigkeit A abhängt, Abhängigkeit A von Abhängigkeit B abhängt und Objekte verkauft, die Typen aus Abhängigkeit B enthalten. Die App und Abhängigkeit A sind beide npm link Abhängigkeit B und erwarten dies in der Lage, Typen daraus zu importieren und sie das gleiche beschreiben zu lassen.

Dies führt zu tiefen Fehlermeldungen, und ich bin kurz davor, alle Eigenschaften von private und protected in meinen Bibliotheken durchzugehen und zu entfernen, da ich bereits so viel Zeit dafür verloren habe ::

TSError: ⨯ Unable to compile TypeScript
tests/helpers/test-application.ts (71,11): Argument of type '{ initializers: Initializer[]; rootPath: string; }' is not assignable to parameter of type 'ConstructorOptions'.
  Types of property 'initializers' are incompatible.
    Type 'Initializer[]' is not assignable to type 'Initializer[]'.
      Type 'Application.Initializer' is not assignable to type 'Application.Initializer'.
        Types of property 'initialize' are incompatible.
          Type '(app: Application) => void' is not assignable to type '(app: Application) => void'.
            Types of parameters 'app' and 'app' are incompatible.
              Type 'Application' is not assignable to type 'Application'.
                Types of property 'container' are incompatible.
                  Type 'Container' is not assignable to type 'Container'.
                    Types of property 'resolver' are incompatible.
                      Type 'Resolver' is not assignable to type 'Resolver'.
                        Types of property 'ui' are incompatible.
                          Type 'UI' is not assignable to type 'UI'.
                            Property 'logLevel' is protected but type 'UI' is not a class derived from 'UI'. (2345)

Ich schätze Sie alle sehr, die sich damit befassen. Dankeschön!

@tomdale Verwenden Sie Webpack, tsc oder ein anderes Build-Tool? Mein Problem scheint nur beim Kompilieren über Webpack aufzutreten (siehe das verknüpfte Repo aus meinem vorherigen Kommentar ).

@seansfkelley Das sieht aus wie https://github.com/TypeStrong/ts-node.

Das ist richtig, es verwendet ts-node (für die Root-Anwendung). Die Abhängigkeiten sind jedoch Pakete, die mit tsc kompiliert wurden.

Ich bin gerade auf dieses Problem gestoßen und es ist ein großes Problem für uns, weil wir versuchen, unser Back-End in viele kleine Bibliotheken aufzuteilen. Während der Entwicklung müssen wir unsere Repos oft mit npm verknüpfen. Das spezielle Problem, auf das ich gestoßen bin und das mich dazu veranlasste, dies zu finden, ist die Verwendung von rxjs Observables und Schnittstellen:


// in repo A
export class HttpAdapter {
    request(url: string, options?: HttpRequestOptionsArgs): Observable<HttpResponse> {
        return Observable.of({});
    }
}

// in repo B
export class HttpRequestAdapter implements HttpAdapter {
    request(url: string, options?: HttpRequestOptionsArgs): Observable<HttpResponse> {
        return Observable.of({});
    }
}

Dies funktioniert, wenn ich nicht npm link , aber wenn ich es tue, bekomme ich:

Error:(10, 14) TS2420:Class 'HttpRequestAdapter' incorrectly implements interface 'HttpAdapter'.
  Types of property 'request' are incompatible.
    Type '(url: string, options?: HttpRequestOptionsArgs) => Observable<HttpResponse>' is not assignable to type '(url: string, options?: HttpRequestOptionsArgs) => Observable<HttpResponse>'.
      Type 'Observable<HttpResponse>' is not assignable to type 'Observable<HttpResponse>'.
        Property 'source' is protected but type 'Observable<T>' is not a class derived from 'Observable<T>'.

Der einzige Vorschlag, den ich machen kann, ist, private zu vermeiden. Aufgrund dieses Problems veröffentliche ich keine Pakete mehr mit private und verwende stattdessen nur JavaScript-ähnliche _ -Präfixe. Ich stoße darauf mit https://github.com/Microsoft/TypeScript/issues/7755, was eine ähnliche Diskussion darüber ist, warum private in ein nominales Typensystem anstatt in ein strukturelles System eintritt und es daher auf meinem System verboten hat eigene Projekte, weil es zu einfach ist, Versionsunterschiede zu haben (z. B. NPM 2 oder die Verwendung von npm link ).

@blakeembrey Wenn Sie sagen, vermeiden Sie privat, schlagen Sie vor, dass ich etwas in meinem Code ändern kann? Ich gehe davon aus, dass die Definition des beobachtbaren Typs das Problem ist, nicht wahr?

@ Jeffwhelpley Ja, sorry, du Observable . Leider ist der Ratschlag zur Vermeidung von private sehr gering und auf Sie nicht vollständig anwendbar. 😄 Vielleicht können Sie ein Problem mit rxjs über die Verwendung von private in ihren öffentlichen Schnittstellen?

Bearbeiten: Ich habe meistens Kommentare abgegeben, weil ich das Problem früher verfolgt und es vermieden hatte, mich meinen eigenen Erfahrungen anzuschließen, aber ich dachte, ich könnte meine Gedanken auch wieder aufschreiben, stattdessen ähneln sie https://github.com/Microsoft/TypeScript/issues/ 6496 # issuecomment -255232592 (wo @tomdale vorschlägt, private und protected eliminieren, habe ich vor einiger Zeit

Ich hatte den Eindruck von @mhegazy, dass er das Gefühl hatte, dass es kein Problem mit npm link . Aber es scheint uns und andere immer noch zu plagen. Ich bin mir also nicht sicher, wo dieses Problem steht? Ist es ein anerkanntes Problem mit TS 2.0+ oder fehlt mir nur irgendwo eine Problemumgehung?!?

Ich bekomme das gleiche Problem und es scheint nicht durch npm link . Ich bekomme es immer noch, wenn ich es mit npm install file.tar.gz installiere. Hier ist der Fehler:

app/app.component.ts(46,5): error TS2322: Type 'Observable<boolean | Account>' is not assignable to type 'Observable<boolean | Account>'.
  Property 'source' is protected but type 'Observable<T>' is not a class derived from 'Observable<T>'.

So sieht mein app.component.ts aus:

export class AppComponent implements OnInit {
  private user$: Observable<Account | boolean>;
  private loggedIn$: Observable<boolean>;
  private login: boolean;
  private register: boolean;

  constructor(public stormpath: Stormpath) {}

  ngOnInit() {
    this.login = true;
    this.register = false;
    this.user$ = this.stormpath.user$;
    this.loggedIn$ = this.user$.map(user => !!user);
  }

Es beschwert sich über die this.user$ Linie. Stormpath hat user$ wie folgt definiert:

@Injectable()
export class Stormpath {

  user$: Observable<Account | boolean>;

@xogeny Seltsam , mein Verständnis war, dass die Definitionsidentität an den Speicherort der Datei gebunden war, was bedeuten würde, dass sie immer Probleme mit npm link (da für die Abhängigkeit npm link ed eigene Abhängigkeiten installiert wären). . Möglicherweise wurde die Definitionsidentität geändert. Die Verwendung von Datei-Hashes ist möglicherweise eine gute Lösung für TypeScript. Leider gibt es nur ein Dutzend verschiedene Möglichkeiten, um doppelte Module in JavaScript zu erhalten ( npm install von GitHub, npm install , manuelle Klone, Versionskonflikte können sogar dazu führen, dass dieselbe Version an verschiedenen Orten landet Funktionsweise des Modulauflösungsalgorithmus des Knotens usw.).

@ Blakeembrey Vielleicht. Aber worum ging es dann ?

Beachten Sie, ich beschwere mich nicht. Ich versuche nur herauszufinden, ob es Hoffnung gibt, dass dies gelöst wird oder nicht. Es ist aus all den Gründen, die @jeffwhelpley erwähnt hat, ein schwerer Dorn im

@xogeny Ich weiß, ich versuche es auch, ich würde gerne sehen, dass es richtig gelöst wird. Ich habe die verknüpften Probleme gelesen, aber sie sind alle darauf ausgelegt, den Realpfad eines Symlinks zu lösen, der impliziert, wenn Sie zwei (echte) Dateien haben Sie werden immer noch Konflikte verursachen, weil sie sich an verschiedenen Orten auflösen. Was passiert, wenn Sie npm link von einem Projekt in ein anderes wechseln, da beide ihre eigenen Abhängigkeiten haben, die sich durch wieder exportierte Symbole aus dem Paket npm link ed unterscheiden können.

Bearbeiten: Ich kann bestätigen, dass alle Probleme auf zwei Dateien zurückzuführen sind. npm link würde es auslösen, weil es einfach ist, eine Abhängigkeit in einem Repo zu haben, die Sie gerade verlinkt haben und die dieselbe Abhängigkeit wie in dem Projekt hat, mit dem Sie verlinkt haben. Ein einfacher Repro wäre, ein npm install derselben Abhängigkeit auf zwei verschiedenen Ebenen einer Anwendung auszuführen und sie auf Fehler zu achten.

image

An alle, die diesem Thread folgen ... Ich habe die hier beschriebene Problemumgehung ausprobiert und sie scheint (bisher) zu funktionieren.

Ich habe diesen Fehler reproduziert.

mkdir a; cd a
npm install rxjs
echo 'import * as rx from "rxjs"; export const myObservable: rx.Observable<number>;' > index.d.ts
echo '{ "name": "a" }' > package.json

cd ..; mkdir b; cd b
npm install rxjs
npm link ../a
echo 'import * as rx from "rxjs"; import * as a from "a"; const x: rx.Observable<number> = a.myObservable;' > index.ts
tsc index.ts --target es6 --moduleResolution node

Da es zwei Installationen von rxjs , erhalten wir:

index.ts(1,59): error TS2322: Type 'Observable<number>' is not assignable to type 'Observable<number>'.
  Property 'source' is protected but type 'Observable<T>' is not a class derived from 'Observable<T>'.

Ich habe eine Problemumgehung, die sich hervorragend für die Befehlszeile eignet, aber Visual Studio ist immer noch durcheinander: https://github.com/Microsoft/TypeScript/issues/11107#issuecomment -254003380

Meine neue Problemumgehung für Windows + Visual Studio 2015 besteht darin, meine Ordner xlib Library src und dist in die Ordner node_modules\xlib\src und node_modules\xlib\dist kopieren des konsumierenden Projekts.

Hier ist der wesentliche Teil meines Robocopy-Batch-Dateiskripts, wenn jemand es möchte:

:rerunloop
    <strong i="14">@echo</strong> watching for changes to project files..............  (Ctrl-C to cancel)

    <strong i="15">@rem</strong> xlib --> blib and slib
    <strong i="16">@robocopy</strong> .\xlib\src .\blib\node_modules\xlib\src *.*  /MIR /NJH /NJS /NDL /XD .git
    <strong i="17">@if</strong> NOT "%errorlevel%" == "0" (
        <strong i="18">@rem</strong> copy occured, so copy both

        <strong i="19">@robocopy</strong> .\xlib\dist .\blib\node_modules\xlib\dist *.*  /MIR /NJH /NJS /NDL /XD .git   
        <strong i="20">@robocopy</strong> .\xlib\src .\slib\node_modules\xlib\src *.*  /MIR /NJH /NJS /NDL /XD .git     
        <strong i="21">@robocopy</strong> .\xlib\dist .\slib\node_modules\xlib\dist *.*  /MIR /NJH /NJS /NDL /XD .git

        <strong i="22">@rem</strong>  set the src dirs readonly
        <strong i="23">@attrib</strong> +R .\blib\node_modules\xlib\src\*  /S /D
        <strong i="24">@attrib</strong> +R .\slib\node_modules\xlib\src\*  /S /D
    )
    <strong i="25">@timeout</strong> /t 1 /nobreak > NUL
<strong i="26">@goto</strong> rerunloop

Es tut uns leid, dass wir dieses Problem erneut behoben haben, aber es ist eine schwerwiegende Belastung für unser Projekt, nicht in der Lage zu sein, npm link während wir Änderungen vornehmen. Ich würde gerne mit einer PR helfen, wenn einer der aktuellen TypeScript-Mitwirkenden mir eine kleine Anleitung geben könnte, wo ich anfangen soll, in der Codebasis zu suchen.

Ich kämpfe auch mit diesem. Wir haben TS ausgehend von einer kleinen App übernommen, jetzt haben wir es in Submodule aufgeteilt und sie verknüpft und… BOOM. TS wird nicht mehr kompiliert. Ist dies immer noch ein Problem in allen TS-Dist-Tags? Ich erlebe dies derzeit in @rc (2.1.1).

@heruan und @jeffwhelpley können Sie typescript@next ausprobieren, wir haben einige verwandte Probleme behoben. Wenn das Problem weiterhin auftritt, geben Sie bitte weitere Informationen zu Ihrem Projekt-Setup an.

@mhegazy Ich bin auf Version 2.2.0-dev.20161129 und habe immer noch das Problem. Das spezielle Problem ist, dass ich ein Projekt (nennen wir es ProjectA) habe, das eine "Schnittstelle" enthält (unter Verwendung einer Klasse, aber so kann ich die Klasse als Token für Angular 2 DI verwenden) wie folgt:

export class ServerAdapter {
    start(opts: ServerOptions): Observable<any> {
        return null;
    }
}

Dann in einem völlig separaten Projekt (nennen wir es ProjectB), das eine Klasse hat, die die Schnittstelle aus dem ersten Projekt wie folgt implementiert:

export class RestifyServerAdapter implements ServerAdapter {
    start(opts: ServerOptions): Observable<any> {
        let server = restify.createServer();
        this.addPreprocessors(server);
        this.addRequestHandler(server, opts);
        return this.startServer(server, opts);
    }

   // more stuff here that is not relevant to this issue
}

Wenn ich ein normales Typoskript für ProjectB kompiliere, funktioniert es einwandfrei. Aber wenn ich npm link ProjectA aus dem ProjectB-Stammverzeichnis habe und dann tsc erneut ausführe, erhalte ich:

Types of property 'start' are incompatible.
    Type '(opts: ServerOptions) => Observable<any>' is not assignable to type '(opts: ServerOptions) => Observable<any>'. Two different types with this name exist, but they are unrelated.
      Type 'Observable<any>' is not assignable to type 'Observable<any>'. Two different types with this name exist, but they are unrelated.
        Property 'source' is protected but type 'Observable<T>' is not a class derived from 'Observable<T>'.

Ich konnte in einem Scheinprojekt nicht replizieren. Ich glaube, ich vermisse die Ursache des Problems, daher kann ich es nicht replizieren. @jeffwhelpley können Sie ein Scheinprojekt veröffentlichen, das das Problem repliziert? Ich denke, ein Lerna-Projekt sollte in Ordnung und leicht testbar sein.

@heruan Ich werde versuchen, das einzurichten.

Eins, zu Ihrer Information. Ich glaube, ich habe vielleicht eine Lösung gefunden. Das Problem ist behoben, wenn ich sowohl in ProjectA als auch in ProjectB npm link rxjs . Diese Art von ist sinnvoll, da in diesem Fall sowohl ProjectA als auch ProjectB genau dieselben rxjs-Dateien verwenden. Ohne das verwenden sie technisch unterschiedliche Dateien (obwohl dieselbe Version):

Wenn Sie nur npm link ProjectA von ProjectB haben, dann:

  • ProjectB zeigt auf node_modules / rxjs
  • ProjectA existiert als Symlink in node_modules / ProjectA und die rxjs, auf die es verweist, befinden sich unter node_modules / ProjectA / node_modules / rxjs

Wenn Sie jedoch in beiden npm link rxjs angeben, werden diese beiden rxjs-Referenzen mit demselben genau globalen npm-Speicherort verknüpft.

Wie auch immer, das ist offensichtlich immer noch nicht ideal, aber zumindest etwas, das uns vorwärts bringen kann.

Auch ... nicht sicher, ob dies relevant oder wichtig ist (wird angezeigt, sobald ich das Testprojekt eingerichtet habe), aber meine beiden Bibliotheken (dh ProjectA und ProjectB) sind tatsächlich private npm-Repos.

Vielen Dank an @jeffwhelpley für den Hinweis, aber da ich Lerna verwende, sind alle Module bereits miteinander verknüpft, sodass sie dieselbe Datei lesen, aber ich denke, der TS-Compiler berücksichtigt den Verknüpfungspfad und nicht den tatsächlichen. Ich kann mich irren, da ich mich nicht in einem Scheinprojekt reproduzieren kann und wirklich verrückt werde…

Kann hier jemand dies auf elegante Weise lösen?

Beachten Sie außerdem, dass dies nicht nur ein Problem mit npm link ist, sondern dass Sie dieses Problem auch bei Produktions-Builds erhalten, wenn Ihre freigegebenen Abhängigkeiten auf eine andere Version verweisen.

dh. ProjectA benötigt [email protected] und ProjectB verwendet [email protected]

Wenn Sie ProjectA als Abhängigkeit in ProjectB installieren, haben Sie auch doppelte Typen, da es beispielsweise zwei Observable -Deklarationen gibt, eine in node_modules/rxjs und eine in node_modules/project_a/node_modules/rxjs

Sie können dies umgehen, indem Sie zulassen, dass die rxjs-Version in ProjectA so etwas wie ~4.9.0 , sodass npm install keine eigene Version herunterladen muss und stattdessen die ProjectB-Version verwendet. Beachten Sie jedoch, dass dies nicht nur ein Problem des Entwicklungsworkflows ist.

Poste hier gemäß dem Vorschlag von @ andy-ms. Versuchte es gestern erneut mit der neuesten Version 2.0.x und hatte es immer noch.

Ich erhalte dies mit den Eingaben für Angular 1: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/10082#issuecomment -253023107

Bin heute wieder darauf gestoßen, speziell auf das Problem mit Symlinks. Mein Setup ist ungefähr so:

node_modules/
folder
  another_folder
    node_modules/ (symlinked to ../../node_modules)
    app/ (angular1 app in typescript)
    tsconfig.json
    (other build files)

Wenn ich nur @types/angular , läuft tsc einwandfrei. Wenn ich die gesamte Suite habe ( @types/angular-{animate,cookies,mocks,resource,route,sanitize} ), bekomme ich viele Tippfehler:

$ npm run tsc

> [email protected] tsc D:\work\angular.io\public\docs\_examples\upgrade-phonecat-1-typescript\ts
> tsc

../../node_modules/@types/angular/index.d.ts(17,21): error TS2300: Duplicate identifier 'angular'.
../../node_modules/@types/angular/index.d.ts(18,21): error TS2300: Duplicate identifier 'ng'.
app/app.animations.ts(5,3): error TS2339: Property 'animation' does not exist on type 'IModule'.
app/app.config.ts(6,45): error TS2305: Module 'angular' has no exported member 'route'.
app/core/checkmark/checkmark.filter.spec.ts(5,22): error TS2339: Property 'mock' does not exist on type 'IAngularStatic'.
app/core/phone/phone.service.spec.ts(18,22): error TS2339: Property 'mock' does not exist on type 'IAngularStatic'.
app/core/phone/phone.service.spec.ts(23,18): error TS2339: Property 'expectGET' does not exist on type 'IHttpBackendService'.
app/core/phone/phone.service.spec.ts(30,18): error TS2339: Property 'verifyNoOutstandingExpectation' does not exist on type 'IHttpBackendService'.
app/core/phone/phone.service.spec.ts(31,18): error TS2339: Property 'verifyNoOutstandingRequest' does not exist on type 'IHttpBackendService'.
app/core/phone/phone.service.spec.ts(39,18): error TS2339: Property 'flush' does not exist on type 'IHttpBackendService'.
app/core/phone/phone.service.ts(5,33): error TS2305: Module 'angular' has no exported member 'resource'.
app/phone-detail/phone-detail.component.spec.ts(5,22): error TS2339: Property 'mock' does not exist on type 'IAngularStatic'.
app/phone-detail/phone-detail.component.spec.ts(18,46): error TS2305: Module 'angular' has no exported member 'route'.
app/phone-detail/phone-detail.component.spec.ts(20,20): error TS2339: Property 'expectGET' does not exist on type 'IHttpBackendService'.
app/phone-detail/phone-detail.component.spec.ts(32,20): error TS2339: Property 'flush' does not exist on type 'IHttpBackendService'.
app/phone-detail/phone-detail.component.ts(7,37): error TS2305: Module 'angular' has no exported member 'route'.
app/phone-list/phone-list.component.spec.ts(6,22): error TS2339: Property 'mock' does not exist on type 'IAngularStatic'.
app/phone-list/phone-list.component.spec.ts(15,20): error TS2339: Property 'expectGET' does not exist on type 'IHttpBackendService'.
app/phone-list/phone-list.component.spec.ts(26,20): error TS2339: Property 'flush' does not exist on type 'IHttpBackendService'.
node_modules/@types/angular-resource/index.d.ts(192,40): error TS2305: Module 'angular' has no exported member 'resource'.
node_modules/@types/angular/index.d.ts(17,21): error TS2300: Duplicate identifier 'angular'.
node_modules/@types/angular/index.d.ts(18,21): error TS2300: Duplicate identifier 'ng'.

Ich habe es behoben, indem ich die Basis ../../node_modules/@types als typeRoots zu meinem tsconfig.json hinzugefügt habe:

    "typeRoots": [
      "../../node_modules/@types/"
    ]

Ich habe versucht, die lokalen node_modules/@types hinzuzufügen, aber das hat nicht funktioniert.

@heruan Ein Hack, den ich begonnen habe, besteht darin, mein eigenes npm-Skript zum Verknüpfen / Aufheben der Verknüpfung zu implementieren, anstatt die lerna-Funktionalität zu verwenden. Sie könnten also so etwas wie lerna run link und dann in all Ihren package.json-Dateien ein npm-Skript namens link das alle npm-Verknüpfungen ausführt, einschließlich (in meinem Fall) npm link rxjs . Es scheint in Ordnung zu funktionieren, nicht definitiv nicht ideal.

@ Jeffwhelpley Kannst du deine Lösung hier teilen?

@yvoronen Ich kann nicht meinen gesamten Code lerna , um alle meine lokalen Projekte zu verwalten und dann lerna run link auszuführen. Unter den Kulissen ruft dies npm run link in jedem der Stammordner meines Projekts auf. Sie müssen also das Skript link in Ihrer package.json wie folgt definieren:

  "scripts": {
    "link": "npm link my-local-project1 && npm link my-local-project2 && npm link rxjs || true",
    "unlink": "npm unlink my-local-project1 && npm unlink my-local-project2 && npm unlink rxjs && npm i || true"
  }

Hoffentlich macht das Sinn, aber lassen Sie mich wissen, wenn Sie Fragen haben.

Ich wollte ein Update bereitstellen. Nach einem spontanen Austausch mit @mhegazy denken wir

  • Eine Lösung, bei der wir das Konzept der Unterscheidung von Paketen anhand ihrer Version sowie ihres Auflösungsnamens in Betracht ziehen. Ich habe keine vollständigen Details darüber, was daran beteiligt sein würde.
  • Eine andere Möglichkeit besteht darin, den Pfad vollständig zu erweitern, um die "wahre" Identität eines Symlinks zu erhalten. Ich glaube, dies ist einfacher, aber eingeschränkter, wenn es darum geht, dasselbe Paket in verschiedenen Versionen zu verarbeiten, aber es hilft, eine anständige Anzahl von Fällen zu lösen.

Sind Sie sicher, dass Ihr Kommentar in diese Ausgabe gehört? Es klingt komplett
anders.

Am Do, 12. Januar 2017, 03:14 Uhr schrieb Nikos [email protected] :

Beachten Sie, dass ich keine Typen oder npm link AFAIK verwende.

[Bild: Bild]
https://cloud.githubusercontent.com/assets/216566/21887548/451d059c-d8b8-11e6-86d1-50afae4e5c2f.png

- -
Sie erhalten dies, weil Sie kommentiert haben.
Antworte direkt auf diese E-Mail und sieh sie dir auf GitHub an
https://github.com/Microsoft/TypeScript/issues/6496#issuecomment-272137732 ,
oder schalten Sie den Thread stumm
https://github.com/notifications/unsubscribe-auth/AAUAmcMXodOvU7coymMqGzTofD4pMagpks5rRgsogaJpZM4HFcWl
.

@dobesv es ist eigentlich der ganze Grund, warum Sie das Problem überhaupt sehen. TypeScript erkennt die Klassendeklaration als zwei separate Deklarationen, da der verknüpfte Pfad nicht vom wahren Pfad unterschieden werden konnte. Die Lösung ist entweder zu

  1. Erweitern Sie den Symlink.
  2. Überprüfen Sie, ob das enthaltende Paket identisch ist.

@DanielRosenwasser Entschuldigung, mein Kommentar war eine Antwort auf den Kommentar eines anderen "Am Do, 12. Januar 2017, 03:14 Uhr Nikos @ . * > Schrieb" ... wer das ist und was sie sagten, ich erinnere mich nicht mehr, ich glaube sie fragten nach einem Problem in diesem Kommentarthread, das nichts mit dem npm-Link zu tun hatte.

Aber während ich hier bin, sollte ich erwähnen, dass die Art und Weise, wie der Dateiname bei Typen eine Rolle spielt, etwas Komisches ist. Heute hatte ich ein Problem mit RxJS, bei dem es sich beschwerte, dass die eine oder andere Methode in Observable nicht definiert war. Der Grund war, dass die HTTP-Bibliothek eine eigene private Kopie von rxjs hatte, die sich von allen anderen unterschied. Tatsächlich habe ich in meinem node_modules-Baum vier verschiedene Kopien von rxjs gefunden.

Dies scheint ein problematischer Ansatz zu sein, der weiterhin problematisch und verwirrend sein wird.

Wenn dieses ganze Konzept des Dateinamens, der irgendwie eine Rolle bei der Identität eines Typs spielt, verschwinden würde, würde dieses Problem mit dem npm-Link wahrscheinlich ebenfalls verschwinden.

Ich bin immer noch ein bisschen unklar, wie das funktionieren würde ... Ich bin neu in TypeScript. Aber das ist der Eindruck, den ich bekomme, dass dieses "Dateiname wichtig" -Ding mich in Verbindung mit den von mir verwendeten Bibliotheken (ionic2 und angle2 und rxjs) ziemlich verwirrt hat.

Das Problem ist, dass der Dateiname immer noch die Identität eines Moduls in Javascript ist und daher nicht vollständig verschwinden kann. Kann jemand die Probleme bei der Verwendung des kanonischen Pfads (Auflösung des Symlinks) in Bezug auf mehrere Paketversionen erläutern? Wenn es in einem Baum mehrere Paketversionen gibt, haben sie mehrere kanonische absolute Pfade, oder?

EDIT: Ich habe dies nach dem Posten erkannt und dieser Kommentar fasst es gut zusammen:
https://github.com/Microsoft/TypeScript/issues/6496#issuecomment -257016094

exclude und compilerOptions.typeRoots werden von tsc vollständig ignoriert. Ich habe alle Kombinationen versucht, um die verknüpften Pfade zu ignorieren, aber es wird einfach nicht
Es sieht das Modul als einen völlig anderen Pfad, als würde es den Symlink auflösen und die ausgeschlossenen Muster nicht verstehen.

Zum Beispiel habe ich G:\www\cim-service-locator npm mit npm link cim-service-locator verknüpft. Auf meinem Projektpfad in G:\www\cim-backend werden die Fehler folgendermaßen angezeigt:

crop

Ich habe alles Mögliche versucht, um Ausschlüsse / Einschlüsse / Typen zu beseitigen. mit 2.2-dev.20170131

Wir haben dieses Problem sowohl mit "npm link" (über ein von @waldekmastykarz gemeldetes SPFx-Problem) als auch ohne "npm link" (siehe Fehler Nr. 11436) festgestellt.

Schließlich wurde mir klar, dass die Strenge des TypeScript-Compilers auf Inkompatibilitäten zurückzuführen ist, die aufgrund des verrückten Designs des Ordners node_modules realistisch auftreten können. Betrachten Sie dieses Beispiel:

A
+---B<strong i="8">@1</strong>
+---C
|   +---B<strong i="9">@2</strong>   <--- first copy of ClassB extends ClassE version 3.4
|   \[email protected]
+---D
|   \---B<strong i="10">@2</strong>   <--- second copy of ClassB extends ClassE version 3.5
\[email protected]

In diesem Beispiel muss B @ 2 in Unterordnern installiert werden, um einen Konflikt mit der Abhängigkeit von A von B @ 1 zu vermeiden. Angenommen, ClassB erstreckt sich von ClassE, und wir haben ungefähr Folgendes:

B / package.json

{
  "name": "B",
  "version": "2.0.0",
  "dependencies": {
    "E": "^3.0.0",
    ...
}

Wenn C ‚s package.json für fragt [email protected] , dann die beiden Kopien von ClassB können sich mit verschiedenen Basisklassenimplementierungen beenden, was bedeutet , dass sie tatsächlich unvereinbar sind. Der Code kann zur Laufzeit fehlschlagen, wenn Sie versuchen, sie austauschbar zu verwenden.

In diesem Beispiel würde TS2345 diesen Fehler verhindern, was sehr schön ist. Dies ist jedoch NICHT unbedingt erforderlich: Wenn der Compiler die beiden ClassB-Kopien als gleichwertig behandelt, ist sein Typsystem intern immer noch konsistent und weist ein deterministisches Verhalten auf.

Dies ist wichtig, da TS2345 für uns meistens Fehlalarme erzeugt. Diese Fehlalarme zwingen die Benutzer dazu, "wie jeder" zu schreiben, wo immer sie Typen zwischen NPM-Paketen teilen, was andere Fehler verursacht. Die Strenge schafft also mehr Probleme als sie löst.

Ich möchte den folgenden Fix vorschlagen:

Wenn ALLE diese Bedingungen erfüllt sind, melden Sie TS2345 NICHT für Klassen mit privaten Mitgliedern:

  1. Die öffentlichen Signaturen sind gemäß der üblichen TypeScript-Ententypisierung kompatibel
  2. Die Klassen werden in NPM-Paketordnern mit demselben Namen und derselben Version definiert (gemäß package.json).
  3. Die Klassen haben denselben relativen Pfad für ihr Modul (z. B. "./lib/blah/Bdts").

Wenn eines dieser Kriterien nicht erfüllt ist, kann TS2345 gemeldet werden.

@iclanton @ nickpape-msft

@seansfkelley Webpack-Fehler wird von TypeStrong / ts-loader # 468 verfolgt

Hallo Leute,
Jemand hat eine Lösung gefunden?
Ich habe das gleiche Problem, wenn ich ein Projekt mit einem anderen mit RxJS verknüpfe.
Vielen Dank ;)

Hallo, eine vorübergehende Problemumgehung besteht darin, Observables, die von einer Abhängigkeit zurückgegeben werden, mit Observable#from .

Noch keine Lösung. ?

Hier scheint es zwei Probleme zu geben.

Benutzer von ts-loader, die fehlerhafte Fehler für doppelte Definitionen erhalten, scheinen durch ungültige Eingaben in die Compiler-API verursacht zu sein. Ein Fix dafür ist in TypeStrong / ts-loader # 468 verfügbar.

Das andere Problem ist, wenn Sie dasselbe Paket (dasselbe npm-Paket + Version) zweimal lokal auf dem Dateisystem installiert haben (ohne npm link ), und zwar in zwei verschachtelten Ordnern, entweder mit Enums oder Klassen mit privaten Mitgliedern Typen aus diesen beiden Paketen würden als inkompatibel fehlschlagen.
Dieses Problem ist etwas komplizierter und erfordert zusätzliche Arbeit, damit der Compiler die Pakete "deduplizieren" kann, bevor sie verarbeitet werden.

Wenn keine dieser beiden Kategorien auf Sie zutrifft, reichen Sie bitte ein neues Problem ein und stellen Sie uns genügend Informationen zur Verfügung, um das Problem lokal zu reproduzieren. Gerne untersuchen wir dies weiter.

Eine bekannte Problemumgehung besteht darin, eine Lösung für mehrere Projekte zu verwenden, mit der doppelte Ordner entfernt werden, dh sichergestellt wird, dass beide Unterordner von node_modules mit demselben Ziel verknüpft sind.

Rush (die wir verwenden) und Lerna sind Beispiele.

@smcatala Sie können Ihre Lösung erklären. Ich muss es dringend beheben. Vielen Dank.

@ leovo2708
Modul 'foo':

import { Observable } from 'rxjs'
export function foo() {
  return Observable.of('foo')
}

Client-Code in einem anderen Modul, der vom Modul 'foo' abhängt:

import { Observable } from 'rxjs'
import { foo } from 'foo'

Observable.of(foo()) // wrap the returned Observable
.forEach(res => console.log(res))

@ leovo2708 Die einfache Lösung besteht darin, nicht npm link .

Mit ts 2.1 konnte ich npm link mit einer einzelnen Bibliothek verwenden (nennen wir es xlib , was mein echtes Beispiel ist), aber Sie müssen sicherstellen, dass die Module Ihrer Bibliothek ( xlib ) Lasten werden im Ordner node_modules des konsumierenden Projekts nicht dupliziert.

Ich mache das mit dem folgenden Workflow

  1. lösche node_modules
  2. npm link xlib , wodurch der sym_link zu xlib in node_modules meines konsumierenden Projekts erstellt wird
  3. npm install das den Rest der Abhängigkeiten meines Consumign-Projekts installiert

Ich habe diese Konversation nicht wirklich verfolgt oder überprüft, ob sich dieses Problem seit 2.2 geändert hat, aber obwohl ich meine Problemumgehung für ts 2.1 teilen würde

Für den Fall, dass es nützlich ist, habe ich hier eine minimale Reproduktion der verschiedenen Definitionen von Enums zusammengestellt: https://github.com/rictic/repro-npm-link-typescript-issue

@mhegazy Wir sehen das obige Problem bei der Verwendung von npm link, obwohl ich nicht denke, dass dies den Rest Ihrer Analyse beeinflusst.

Vielen Dank, hoffe, dass es bald behoben wird. Ich habe jedoch eine neue Lösung verwendet und alle Dateien mit Observable dupliziert. Es ist nicht gut, sondern nur eine temporäre Lösung.

tsconfig.json macht eine Pfadzuordnung verfügbar und fügt doppelte Abhängigkeiten zu paths , sodass diese von der rechten Seite node_modules anstelle der verknüpften geladen wird.

{
  "compilerOptions": {
    "baseUrl": ".", // This must be specified if "paths" is.
    "paths": {
      "@angular/common": ["../node_modules/@angular/common"],
      "@angular/compiler": ["../node_modules/@angular/compiler"],
      "@angular/core": ["../node_modules/@angular/core"],
      "@angular/forms": ["../node_modules/@angular/forms"],
      "@angular/platform-browser": ["../node_modules/@angular/platform-browser"],
      "@angular/platform-browser-dynamic": ["../node_modules/@angular/platform-browser-dynamic"],
      "@angular/router": ["../node_modules/@angular/router"],
      "@angular/http": ["../node_modules/@angular/http"],
      "rxjs/Observable": ["../node_modules/rxjs/Observable"]
    }
  }
}

Ich bin mir nicht sicher, ob ich hier bereits erwähnt habe, aber diese Lösung hat bei mir funktioniert: https://github.com/Microsoft/TypeScript/issues/11916#issuecomment -257130001

Es ist im Grunde dasselbe wie die obige Lösung von

Das ist eine großartige Idee @charpeni. Ich habe diese Pfadeinstellung verwendet, um verschiedene ähnliche Probleme zu umgehen, aber sie scheint auch für dieses Problem ideal zu sein. Tatsächlich frage ich mich, ob die richtige Einstellung von paths im konsumierenden Projekt (und nicht in jedem konsumierten Projekt) den TypeScript-Compiler von der folgenden Knotenauflösung ablenken könnte. Wenn das funktioniert, wäre es ein O (1) -Hack anstelle eines O (n) -Hacks. Im Wesentlichen würde ein solches Schema die Knotenauflösung statisch ausführen und dann die Ergebnisse in tsconfig einfügen.

Ich experimentiere halb öffentlich mit diesen Dingen, wenn jemand zuschauen will (oder helfen will ...). Ich werde wahrscheinlich die obige Idee als nächstes versuchen.

https://github.com/OasisDigital/many-to-many-angular

Zur einfacheren Verwendung können Sie die Pfade auch wie folgt festlegen:

{
    "compilerOptions": {
        "baseUrl": ".", // This must be specified if "paths" is.
        "paths": {
            "@angular/*": ["../node_modules/@angular/*"],
            "rxjs/*": ["../node_modules/rxjs/*"]
        }
    }
}

npm link ist ein entscheidender Teil des Workflows, wenn mit mehreren Paketen gearbeitet wird, im Gegensatz zu einer Mono-Repo-Architektur. TS sollte erkennen können, dass die beiden Pakete identisch und nicht fehlerhaft sind

@charpeni Ich konnte die Laufen bringen. Nur um klar zu sein, zu welcher tsconfig.json muss dies hinzugefügt werden? Das Root-Paket oder das verknüpfte Paket?

Ich habe auch dieses Problem. Es begann plötzlich am Montag und ich bin mir nicht sicher warum. Dies behindert die Entwicklung wirklich, insbesondere wenn es darum geht, Pakete für unsere Projekte zu entwickeln. Ich habe zahlreiche Problemumgehungen versucht, um dies zu beheben. Wenn Sie in Windows mklink /j ausführen, tritt dieses Problem weiterhin auf, sodass es sich nicht um ein Problem mit npm-Links handelt. Wenn jemand eine Problemumgehung oder eine Lösung hat, wäre dies eine große Hilfe.

Meine Problemumgehung besteht darin, jedes einzelne "doppelte" Paket sowohl im Root-Paket als auch in der Abhängigkeit mit npm zu verknüpfen, da sie dann wieder auf dieselben Dateien verweisen.

Übrigens hat dieses Problem nichts mit @types zu tun

Am Ende haben wir das Glob-Muster verwendet.

@felixfbecker Die Implementierung finden Sie hier: https://github.com/sherweb/ng2-materialize/blob/master/demo-app/tsconfig.json#L19 -L22

Ich habe ein ähnliches Problem, außer dass es vollständig mit @ types / node zusammenhängt.

libA hängt von @ node / types ab
libB hängt von libA und @ node / types ab
libC hängt von libA, libB und @ node / types ab

libA baut gut.
libB npm ist mit der libA-Builds-Datei verknüpft.
libC npm, das mit libA und libB verknüpft ist, schlägt die Typprüfung mit Fehlern wie z

libC/node_modules/@types/node/index.d.ts(102,6): Duplicate identifier 'BufferEncoding'.
libC/node_modules/libB/node_modules/@types/node/index.d.ts(102,6): Duplicate identifier 'BufferEncoding'.
libC/node_modules/libB/node_modules/libA/node_modules/@types/node/index.d.ts(102,6): Duplicate identifier 'BufferEncoding'.

Ich habe ohne Glück versucht, mit "types" und "typeRoots" herumzuspielen.

@charpeni Es sieht so aus, als ob Ihr Projekt auch von @ types / node abhängt. Haben Sie einen Einblick in die Lösung meines Problems oder eine Problemumgehung?

@nicksnyder könnte daran @types/node eine globale Deklaration ist, dh Sie können dieselben Namen nicht zweimal definieren. Dies ist der Grund, warum es am besten ist, wenn Pakete nicht von Umgebungstypen abhängen. Diese sollten vom Benutzer bereitgestellt werden:
https://github.com/Microsoft/types-publisher/issues/107

@nicksnyder Ich hatte ein ähnliches Problem und konnte es

@felixfbecker Ich habe überprüft, ob alle Projekte von derselben Version des Knotens abhängen.

FWIW libA ist https://github.com/Microsoft/vscode-languageserver-node/tree/master/jsonrpc , libB ist https://github.com/Microsoft/vscode-languageserver-node/tree/master/client und libC ist meine eigene VS Code Erweiterung.

@uncleramsay wie genau hast du npm link @types/node ?

???
cd libA; npm link @types/node
cd libB; npm link @types/node
cd libC; npm link @types/node

Ich möchte die Verknüpfungslösung ausführen, habe dies jedoch auch durch Löschen der Abhängigkeit @ types / node in libA und libB behoben und eine refs.d.ts hinzugefügt, die lokale Verweise auf die Kopie des Knotens von libC enthält.

/// <reference path='../../../path/to/libC/node_modules/@types/node/index.d.ts'/>

Ich habe festgestellt, dass ich Probleme aus der Beschreibung im Kommentar unter https://github.com/Microsoft/TypeScript/issues/9091#issuecomment -225303098 beheben konnte

Wir haben nur Unterstützung für die Symlink-Auflösung für Module hinzugefügt ...

An verschiedenen Stellen in der Codebasis, als wir zwei verschiedene Referenzstile verwendeten:

/// <reference path="../node_modules/@types/library" />
/// <reference types="library" />

Diese beiden sind nicht kompatibel, wenn node_modules miteinander verknüpft sind, da die Modulauflösung (mit types= ) auf den Realpath erweitert wird, path= jedoch nicht. Dies führt zu zwei verschiedenen Dateien, auf die beim Kompilieren mit tsc --listFiles verwiesen wird, dem Symlink und dem Realpath.

Die Lösung, die wir gewählt haben, war, das eine oder das andere zu verwenden, aber niemals beides. Es hat auch geholfen, typeRoots: [] in der tsconfig anzugeben, um zu vermeiden, dass der Compiler die Typen automatisch von node_modules/@types lädt, wenn der Stil reference path= .

Ich glaube, die Präferenz für die Zukunft (zumindest für uns) ist es, den types= -Stil zu bevorzugen.

Im Idealfall ist es jedoch vorzuziehen, auf den Realpfad in reference path= zu erweitern und nach doppelten übereinstimmenden Pfaden zu suchen, um solche Probleme zu vermeiden.

Hoffe das hilft jemandem.

@nicksnyder Sie sollten in der Lage sein, so etwas zu tun:

cd libA/node_modules/@types/node; npm link
cd libB; npm link @types/node
cd libC; npm link @types/node

Auf diese Weise zeigen B & C auf genau die gleichen Dateien wie A.

@unclerams können sich bewusst sein, dass es sich dann um dieselben Versionen handelt, die sie zuvor möglicherweise noch nicht hatten

Können Peer-Abhängigkeiten keine Lösung dafür sein?
http://codetunnel.io/you-can-finally-npm-link-packages-that-contain-peer-dependencies/

Peer-Abhängigkeiten wurden für eine Situation erfunden, in der ein Plug-In sagen möchte, was dazu gehört. Sie arbeiten in Ordnung für diesen Fall. Sie verursachen jedoch viele Probleme, wenn Benutzer beginnen, alle ihre Abhängigkeiten in Peer-Abhängigkeiten zu konvertieren, in der Hoffnung, Doppelarbeit bei der "npm-Installation" zu vermeiden.

Wir haben Monate damit verbracht, sie aus unseren internen Git-Repos zu verbannen. Peer-Abhängigkeiten ermöglichen es Ihnen, ein Side-by-Side-Versionsproblem zu lösen, indem Sie es gegen mehrere neue Probleme eintauschen:

  • Der gesamte Baum wird invertiert, dh jedes Paket wird jetzt dafür verantwortlich, eine harte Abhängigkeit von Paketen zu übernehmen, die früher indirekte Abhängigkeiten waren, in vielen Fällen ohne eine Ahnung, wofür es ist

  • Wenn eine Peer-Abhängigkeit entfernt wird, werden diese harten Abhängigkeiten wahrscheinlich nie entfernt

  • Paketautoren sind versucht, breite Bereiche für ihre Peer-Versionsmuster zu verwenden, und behaupten, mit Versionen zu arbeiten, gegen die sie nie getestet haben. kaputte Builds werden plötzlich zum Problem des Verbrauchers

Gut gesagt.

Problemumgehungen

Hier sind 3 Optionen für Problemumgehungen, die ich verwendet habe:

Option 1: Verwenden Sie vscode nicht Visual Studio

Der tsc -Compiler ist viel verzeihender als VS2017, wahrscheinlich weil VS2017 den Code (einschließlich des verknüpften node_modules ) crawlt, um eine nette Intelligenz bereitzustellen, und daher verwirrt wird. Ich habe jedoch große komplexe Multi-Npm-Modul-Projekte. Verwenden Sie also VS2017. Lesen Sie also Option 2 und 3, wenn Sie ähnliche Anforderungen haben.

Option 2: d.ts ausgeben

Wenn Sie outDir und rootDir (in Ihrem tsconfig.json ) verwenden, muss Ihr symlinked lib-Modul d.ts Deklarationen ausgeben und diese Deklarationen müssen in den lib-Modulen sein package.json types Eigenschaft.

Hier ist ein Beispiel dafür, wie tsconfig.json Ihres lib-Moduls aussehen sollte

{
  "compileOnSave": true,
  "compilerOptions": {
    "module": "commonjs",
    "sourceMap": true,
     "declaration": true,
    "jsx": "react",
    "newLine": "LF",
    "pretty": true,
    "stripInternal": true,
    "diagnostics": true,
    "target": "es5",
    "moduleResolution": "node",
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "rootDir": "./src",
   //workaround for npm linking projects and associated dupe identifier bugs: https://github.com/Microsoft/TypeScript/issues/9566#issuecomment-287633339
    "baseUrl": "./",
    "paths": {
      "*": [
        "node_modules/@types/*",
        "*",
        "custom-dts/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "dist"
  ]
}

und das package.json Ihres lib-Moduls sollte ungefähr Folgendes enthalten:

  "main": "./dist/_index.js",
  "types": "./dist/_index.d.ts",

Diese Option funktioniert gut. Das Hauptproblem besteht darin, dass in Visual Studio beim Debuggen oder "Zur Definition gehen" oder "Alle Referenzen anzeigen" die d.ts angezeigt werden, nicht die tatsächlichen Typoskript-Quelldateien, wodurch die Hauptvorteil von Visual Studio (Navigation in großen Projekten)

Wenn Sie ein aktuelles Beispiel dafür in freier Wildbahn sehen möchten, schauen Sie sich das npm-Modul xlib v8.5.x an

Option 3: .js inline mit der Quelle ausgeben (meine Lieblingsauswahl)

Sie können Ihre .ts -Dateien direkt zum Eingeben von verknüpften lib-Modulen verwenden! aber nur, wenn Sie nicht die Datei outDir`` and rootDir in your tsconfig.json``` verwenden. Dadurch funktioniert die VS2017-Referenzierung ordnungsgemäß. Hier sind die Konfigurationseinstellungen, die Sie benötigen:

{
  "compileOnSave": true,
  "compilerOptions": {
    "module": "commonjs",
    "sourceMap": true,
     //"declaration": true,
    "jsx": "react",
    "newLine": "LF",
    "pretty": true,
    "stripInternal": true,
    "diagnostics": true,
    "target": "es5",
    "moduleResolution": "node",
    "forceConsistentCasingInFileNames": true,
    //"outDir": "./dist",
    //"rootDir": "./src",
   //workaround for npm linking projects and associated dupe identifier bugs: https://github.com/Microsoft/TypeScript/issues/9566#issuecomment-287633339
    "baseUrl": "./",
    "paths": {
      "*": [
        "node_modules/@types/*",
        "*",
        "custom-dts/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "dist"
  ]
}

und das package.json Ihres lib-Moduls sollte geändert werden in:

  "main": "./src/_index.js",
  "types": "./src/_index.ts",

Vorsichtsmaßnahmen (Dinge, die mit Option 3 nicht funktionieren)

Die oben genannten Problemumgehungen funktionieren nur, wenn jedes lib-Modul KEINE redundanten xlib -Bibliothek die Typdefinitionen @types/async offenlegen. Aber dann hatte ich eine andere Bibliothek, die auch unabhängig auf @types/async verwies. Wenn Sie die .ts -Dateien direkt zum Eingeben verwenden, importiert tsc async aus zwei lib-Modulen, was dazu führt, dass verschiedene Formen von duplicate identifier Problemen auftreten. Um dies zu lösen, müssen Sie entweder nicht dasselbe @types aus mehreren lib-Modulen importieren oder die Option 2 .d.ts Workaround verwenden

Zusammenfassung

Ich hoffe, dies kann Ihnen die Stunden ersparen, die ich gebraucht habe. Insgesamt ist dies äußerst schmerzhaft, und ich hoffe, dass das Typoskript-Team symlinked Module reparieren kann. Aber zumindest funktioniert es jetzt irgendwie (vor 2.x war es im Grunde unmöglich)

Die von @mhegazy in https://github.com/Microsoft/TypeScript/issues/11916#issuecomment -257130001 (eine Variante von Workaround 2 @jasonswearingen) veröffentlichte Problemumgehung hat dies für uns gelöst, wenn verknüpfte Module in einem lerna-Projekt verwendet wurden!

Ich dachte nur, ich würde meine Erfahrungen teilen ... versuchen, eine Bibliothek aus einem vorhandenen Projekt zu erstellen / extrahieren, damit die Bibliothek für andere Projekte freigegeben werden kann.

Windows 10 Enterprise
VS 2015 Update 3
Tools für VS2015 2.2.2
VS Code 1.12.2
Typoskript 2.2.2
NPM: 3.10.9
Knoten: 6.9.2

Wir haben ein VS 2015 ASP.MVC-Projekt mit einem Angular 4.1.x-Frontend, aus dem wir einige Komponenten extrahiert haben, um eine gemeinsame Bibliothek zu erstellen, damit sie in anderen Projekten verwendet werden können.

Das Bibliotheksprojekt wird mit VS-Code erstellt und verwendet Rollup, um die Versionen es2015, es5 und umd zusammen mit den entsprechenden d.ts-Dateien in den Ordner dist zu erstellen.

Das Endergebnis sieht ungefähr so ​​aus:

-- dist
    |
    -- mylib
        |-- <strong i="16">@myscope</strong>
            |-- mylib.es5.js
            |-- mylib.js
        |-- bundles
            |-- mylib.umd.js
        |-- src
            |-- [all the d.ts folders/files]
        |-- index.d.ts
        |-- package.json
        |-- public_api.d.ts

Ich habe npm den Ordner dist / mylib mit meinem VS 2015 / Angular 4.1.x-Projekt verknüpft.

Wenn ich versuche, das Projekt in VS 2015 zu kompilieren, erhalte ich den gleichen Nachrichtentyp wie in einigen der oben genannten Situationen für Abonnement, Beobachtbar usw. beschrieben.

Ex: Build: Argument of type 'Subscription' is not assignable to parameter of type 'Subscription'.

Wenn ich das Verzeichnis node_modules vorübergehend aus dem Bibliotheksprojekt lösche, werden neue Fehler angezeigt, die sich darüber beschweren, dass Module nicht gefunden werden können:

ex: Build: Cannot find module 'rxjs/Observable'.

Dies führt mich zu dem Schluss, dass der Typoskript-Compiler beim Kompilieren der Anwendung tatsächlich im Ordner node_modules des Pakets my linked library nach den Moduldefinitionen für meine Bibliothek und nicht im Ordner node_modules der Anwendung sucht.

Mir ist nicht klar, welche der oben vorgeschlagenen Lösungen eine Problemumgehung für dieses Problem darstellen. Könnte mir bitte jemand helfen?

Vielen Dank!

@mikehutter Führen Sie in Ihrem Projekt, das Ihre Bibliothek verwendet (nicht in der Bibliothek selbst), Folgendes in Ihrer tsconfig aus:

    "paths": {
      "rxjs/*": ["../node_modules/rxjs/*"]
    },

Je nachdem, wo sich Ihre tsconfig und Ihr Quellcode befinden, müssen Sie dies möglicherweise geringfügig anpassen.

(Wie andere in diesem Thread würde ich gerne eine Verbesserung von TypeScript sehen, die dies unnötig macht.)

@mikehutter Wir haben kürzlich einige Anleitungen in Angular CLI für die Arbeit mit verknüpften https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/linked-library.md .

@kylecordes ist auf Punkt 👍

Vielen Dank an @kylecordes und @filipesilva! Das war alles was ich brauchte ...

Hallo!

@mhegazy , glaubst du, das wird es auf 2,4 schaffen oder wird es
Es ist sehr schmerzhaft, das Problem zu umgehen, und jedes Projekt muss immer Pfadzuordnungen für Dinge definieren, um die es sich eigentlich nicht kümmern sollte.

Ich hoffe wirklich, diesmal schafft es das in die Veröffentlichung!

Beste,

Ich glaube nicht, dass dies bereits erwähnt wurde, aber die Kurzform, um dieses Problem zu umgehen, ist:

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "*": ["node_modules/*", "*"]
        }
    }
}

Der obige paths -Eintrag besagt im Wesentlichen: Suchen Sie für jedes Modul zuerst im Ordner node_modules im Stammverzeichnis des Projekts nach und greifen Sie dann auf die normale Regel zurück (rekursives Durchsuchen der Verzeichnisse von wo aus) der Import ist erfolgt).

(Bitte korrigieren Sie mich, wenn ich falsch liege, ich bin immer noch ein relativer Neuling bei TS).

Der Eintrag in paths scheint relativ zu baseUrl . Wenn Sie also baseUrl in einem Unterordner festlegen, müssen Sie Ihre Pfaddefinition entsprechend ändern. Z.B:

{
    "compilerOptions": {
        "baseUrl": "./src",
        "paths": {
            "*": ["../node_modules/*", "*"]
        }
    }
}

@fiznool fyi , das ist Teil meiner paths festzulegen, wenn Sie Projekte mit Symlinks verknüpft haben, die dieselben Typisierungen verwenden.

@jasonswearingen dein Beitrag ist viel umfassender als meiner ... danke, dass du das

Wir sehen dies auch in Google-Projekten. Wie hier beschrieben:
https://github.com/Microsoft/TypeScript/issues/9091#issuecomment -306969543

Die oben beschriebenen Problemumgehungen mit baseUrl und Pfaden scheinen nicht zu funktionieren. Tsc übernimmt weiterhin die doppelten Definitionen und keine Kombination von Pfaden / baseUrl / include / exclude / etc. konnte es anders überzeugen.

Ich bin gespannt, wie das normal funktioniert. Wenn Sie ein Projekt haben, das von X abhängt, und auch von Y, das transitiv von X abhängt, wie vermeidet tsc das zweimalige Laden der Typdefinitionen?

@esprehn Ich empfehle Ihnen dringend, meinen Workaround-Beitrag hier zu lesen: https://github.com/Microsoft/TypeScript/issues/6496#issuecomment -302886203

In Bezug auf diesen Link erfordern meine beiden Lösungen (2 und 3) mehr als nur das Festlegen der baseUrl und der Pfade. Wenn dies alles ist, was Sie tun, lesen Sie sie bitte erneut. Der "einfache" Weg ist Lösung 2, aber ich bevorzuge Lösung 3, da sie eine ordnungsgemäße "Navigation zur Definition" über Visual Studio ermöglicht. Das Problem mit Lösung 3 besteht darin, dass externe .d.ts-Definitionen nur einmal in die Abhängigkeitskette geladen werden müssen.

hoffentlich hilft das.

+1 Ich verwende lerna und eine Unterabhängigkeit mit eingeschlossenen Typisierungen wird als "doppelt" gekennzeichnet, wenn sie durch verknüpfte Abhängigkeiten eingeschlossen wird.

Ich kann bei Bedarf Code freigeben.

Lassen Sie bei WebPack wie in Angular-CLI das Angular-CLI-Paket.json auf das RXJS -Paket verweisen und entfernen Sie dann das RXJS-Paket aus dem package.json eines anderen Projekts, das Sie aufgrund des WebPacks nicht benötigen .

Diese Situation kann nicht nur bei Symlinks auftreten, sondern auch bei npm-shrinkwrap.json in einer Abhängigkeit von @types/node in dependencies . Mit Shrinkwrap installiert npm zwei identische Versionen von @types/node in das übergeordnete Paket und in das Shrinkwrap-Paket. Weitere Informationen finden Sie unter

Dies ist auch aufgetreten, wenn Sie ein Reaktionsprojekt verwenden, auf dem @types/react installiert ist, und es mit einer App verknüpfen, die auch @types/react

Ich hatte das gleiche Problem bei der Arbeit mit Paketen mit yarn link .
Rx.js einen Fehler ausgelöst: Type 'Observable<Location[]>' is not assignable to type 'Observable<Location[]>'. Property 'source' is protected but type 'Observable<T>' is not a class derived from 'Observable<T>'

Glücklicherweise habe ich es behoben, indem ich dieselbe Rxj.s -Version in übergeordneten und verknüpften Paketen verwendet habe.
In meinem Fall haben also zwei verschiedene Versionen von Rx.js das Problem verursacht.

Dies ist ein großer Blocker bei der Arbeit mit Monorepos. Hoffe wirklich, dass sich dies nicht länger verzögert und seinen Weg in 2.5 findet.

Bearbeiten: 😮

image

Interessant. Der Monorepo ist das einzige Szenario, in dem mein Team NICHT auf dieses Problem stößt, da die Symlinks alles auf einen gemeinsamen Paketordner verweisen.

Mein Team ist ziemlich häufig auf dieses Problem gestoßen, als es während der Entwicklung unsere eigenen internen Bibliotheken verknüpfte.

Kürzlich haben wir ein Tool namens yalc gefunden, das dies sehr gut mildert und tatsächlich zu einer ziemlich guten Entwicklungsschleife führt. (Als tl; dr werden anstelle der Verknüpfung des gesamten Pakets die vorveröffentlichten Skripte ausgeführt und das Ergebnis in einen verknüpften Ordner kopiert.)

Dieses Problem scheint immer wieder zurückgedrängt zu werden. Könnten wir möglicherweise eine Art Notlösung haben, z. B. einen "Kommentar deaktivieren", wie in # 9448 vorgeschlagen, da dies die Arbeitsabläufe so vieler Menschen wirklich stört?

import { baz$ } from './qux';
function foo (bar$: Observable<any>) {}

foo(baz$);
> Duplicate identifier

// Makes foo's `bar$` type equal to that of `baz$`
foo(/*typescript:identicalIdentifier*/ baz$);

Der "Kommentar deaktivieren" ist nicht viel besser, als einfach überall Typumwandlungen durchzuführen, was in einem großen Projekt ziemlich schmerzhaft ist. Oben habe ich folgende Compileränderung vorgeschlagen:

Wenn ALLE diese Bedingungen erfüllt sind, melden Sie TS2345 NICHT für Klassen mit privaten Mitgliedern:

  1. Die öffentlichen Signaturen sind gemäß der üblichen TypeScript-Ententypisierung kompatibel
  2. Die Klassen werden in NPM-Paketordnern mit demselben Namen und derselben Version definiert (gemäß package.json).
  3. Die Klassen haben denselben relativen Pfad für ihr Modul (z. B. "./lib/blah/Bdts").

Wenn eines dieser Kriterien nicht erfüllt ist, kann TS2345 gemeldet werden.

Eine vereinfachte Lösung wäre auch immer noch besser als die aktuelle Situation, z. B. nur die Nummer 1 berücksichtigen, möglicherweise nur, wenn sich Benutzer über tsconfig anmelden. Die Implementierung sollte ziemlich billig sein.

Dieser Ansatz hat den Vorteil, dass lediglich Fehlalarme deaktiviert werden, die vorhandene Semantik jedoch beibehalten wird. Während die Node_Modules-Remapping-Hacks die Auflösung des NPM-Moduls möglicherweise falsch ändern (z. B. eine Fehlfunktion des Codes in

Um ehrlich zu sein, bin ich mir nicht einmal sicher, ob dies in Typescript "behoben" werden soll, da es auch ein Problem mit einfachem JavaScript gibt: Der Operator instanceof gibt false zurück, wenn sich die Klasse des Objekts von der angegebenen Klasse unterscheidet.

Daher freue ich mich lieber auf eine bessere Alternative zu npm link, die sich möglicherweise zuerst in require () einhakt.

Das ist eine gute Einsicht. Hast du dir pnpm angesehen ? Es ist ein kleiner Schritt vorwärts gegenüber dem aktuellen Design von node_modules, aber ein sehr effektiver, wenn ich es richtig verstehe.

Es geht nicht nur um npm link die ersetzt oder nicht verwendet werden können, sondern darum, mehrere Versionen desselben @types/xxx -Pakets gleichzeitig zu installieren, die häufig aus Abhängigkeiten stammen, die abhängige TypeScript-Deklarationen bereitstellen auf Standarddeklarationen, wie ich und andere Leute berichteten. Die Anzahl solcher Pakete wird mit zunehmender Akzeptanz von TypeScript in der Node-Community zunehmen.

@ Yogu Ich denke, das verwirrt Identität und Gleichheit. Auch wenn Importe desselben Pakets / derselben Version von zwei Speicherorten zwei verschiedene Instanzen eines Typs darstellen können, sind sie dennoch vom gleichen Typ.

Der folgende (gültige) Code fällt mir ein:

type a = { c: string };
type b = { c: string };

function foo (bar: a) {}

const baz: b = { c: 'd' };
foo(baz);

Gleiches sollte für die von uns importierten Bibliotheken gelten.

Die aus den verschiedenen Versionen der Bibliotheken (und den entsprechenden @types -Paketen) importierten Typen können gleich und unterschiedlich sein (wenn die Bibliothek aktualisiert wird, sollte auch die Typdefinition aktualisiert werden, um die Änderungen widerzuspiegeln).

Ich habe gerade eine Änderung zusammengeführt, die versucht, doppelte Pakete anhand ihres Namens und ihrer Version zu erkennen und nur eines zu verwenden. Bitte probieren Sie es mit typescript@next wenn dies das nächste Mal veröffentlicht wird.

Hurra, vielen Dank, dass Sie das behoben haben! :-)

@pgonzal Danke für den Zeiger auf pnpm, das sieht auf jeden Fall interessant aus!

@sompylasar Das @types/node ist ein Sonderfall, aber für @types/react ist hier mein Vorschlag: Fügen Sie alle für die API eines Moduls erforderlichen Abhängigkeiten in das peerDependencies . nicht in dependencies . Dies macht deutlich, dass die Versionen der Abhängigkeiten zwischen dem übergeordneten und dem untergeordneten Modul übereinstimmen (oder zumindest kompatibel sein müssen). Wenn Eltern und Kind Reagieren verwenden, aber keine Objekte von Reaktionstypen austauschen, tritt dieses Problem hier überhaupt nicht auf.

@harangue Wenn eine Klasse in zwei verschiedenen Dateien mit demselben Namen und derselben Struktur zweimal deklariert wird, gibt es immer noch zwei unterschiedliche Klassen, die von JavaScript nicht als gleich angesehen werden. Wie bereits erwähnt, unterscheidet der Operator instanceof weiterhin Instanzen der beiden Klassen.

Sehen Sie sich diese Geige für eine Demonstration an.

Das ist der Grund, warum ich dies lieber auf NPM-Ebene lösen möchte (wir haben also überhaupt keine Mehrfachdeklarationen, wenn dies nicht beabsichtigt ist) als in TypeScript.

@Yogu : +1: Wenn also @types/node ein Sonderfall ist, dh Sie können ein Programm nicht gleichzeitig mit zwei verschiedenen Knotenversionen ausführen, handelt es sich um eine Version und höchstwahrscheinlich um die in der Top-Level-Paket, vielleicht sollte TypeScript es als Sonderfall behandeln, z. B. immer das Top-Level @types/node für jede Abhängigkeit verwenden?

@ andy-ms Danke dafür!

Bitte probieren Sie es mit typescript @ next aus, wenn das nächste Mal veröffentlicht wird.

Ich gehe davon aus, dass das noch nicht passiert ist. Ich habe es mit ein paar Projekten versucht, aber bisher kein Glück. Es wäre toll, ein Update in diesem Thread zu sehen, sobald next verfügbar ist. @ andy-ms

Es sieht so aus, als hätten die täglichen Builds wieder aufgehört. Der letzte war: 2.5.0-dev.20170808 .

cc / @DanielRosenwasser

Ich bin nicht sicher, ob dies damit zusammenhängt, aber wenn ich 2.5.1 versuche, sehe ich nur einen Aspekt eines Moduls, selbst wenn es d.ts an anderer Stelle erweitert.

Wenn ich ein @types für etwas habe, sagen wir @types/mongodb und ich habe eine benutzerdefinierte Deklaration, die dieses Modul erweitert, dh Methoden Promisifizierung hinzufügt, also habe ich jetzt das @types/mongodb das hat Das Modul mongodb und ich haben eine d.ts-Datei in meinem Projekt, die so etwas wie mongo-promisification.d.ts und ein mongodb -Modul enthält.

Mit dem obigen Szenario habe ich also eine Datei mit import {somethingFromTypes} from "mongodb" darüber beschwert, dass die Daten aus dem Typmodul nicht gefunden werden können, obwohl sie dort vorhanden und gültig sind, aber wenn ich import {somethingFromMyExtendingDts} from "mongodb" getan habe, funktioniert das fein.

Beim Kompilieren wird mir nur mitgeteilt, dass das Modul dieses Zeug nicht exportiert, wenn dies der Fall ist, ist dies auch das gewünschte Verhalten, und ich muss nur meine benutzerdefinierten d.ts erneut exportieren oder sollte es sowohl die Typen als auch die Erweiterung d.ts enthalten Ich habe?

Ich verwende den neuesten Test Build (Windows 10 64 Bit) und dies scheint für mich nicht behoben zu sein.

Reproduktion

Struktur

a/
  index.ts
  package.json
b/
  index.ts
  package.json

Lauf

cd a
npm link
cd ../b
npm link a

a / index.ts

import { Observable } from 'rxjs/Observable';

export class Foo {
  public bar: Observable<any>;
}

b / index.ts

import { Foo } from '@rxjs-test/a';
import { Observable } from 'rxjs/Observable';

const baz = new Foo();

function qux (quux: Observable<any>) {}

// TypeError
qux(baz.bar);

Lauf

b>tsc -v
Version 2.6.0-dev.20170826

b>tsc index.ts
index.ts(11,5): error TS2345: Argument of type 'Observable<any>' is not assignable to parameter of type 'Observable<any>'.
  Property 'source' is protected but type 'Observable<T>' is not a class derived from 'Observable<T>'.

@grofit Ich denke, das Problem in Ihrer Situation ist, dass Sie zwei Deklarationen eines Moduls haben, wobei Sie ein Modul und eine Erweiterung benötigen.
Sie sollten in der Lage sein, mongo-promisification.d.ts wie

import * as mongodb from "mongodb"; // import the real mongo

// now augment it
declare module "mongodb" {
    // new stuff...
}

Ohne import Sie sich in einem Umgebungskontext und schreiben eine neue Deklaration, keine Erweiterung.

( Handbuch ref)

Kann bestätigen, dass dies jetzt für mich mit [email protected] funktioniert. Vielen Dank an @ andy-ms - das ist ein Game Changer!

Ich hatte das gleiche Problem, als ich Observable importiertedurch die Bibliothek Typescript zum Angular-Cli-Projekt und die Funktionen verwendeten das Code-Snippet

`` `function getitems (): Beobachtbar
http.get (). map (Antwort: Antwort) => {
Rückkehrresponse.json ();
}}


and when I removed the Observable<T> from function getitems() to not return anything the error disappear.
```function getitems()
http.get().map(response : Response) =>{
return <T> response.json();
}

@ Basel78 Ich würde ein vollständiges Beispiel benötigen, um Ihren Fehler reproduzieren zu können. Stellen Sie außerdem sicher, dass Sie typescript@next Angular-cli verfügt möglicherweise über eine ältere Version, die nicht über die Deduplizierungsfunktion verfügt.

Ich habe versucht, [email protected], aber immer noch viele Fehler TS2300: Doppelte Kennung.
Leider kann ich nicht das ganze Projekt teilen. Aber hier sind einige Details:
tsconfig des npm-link-ed-Pakets:

    "compilerOptions": {
        "module": "amd",
        "target": "es3",
        "sourceMap": true,
        "noEmitHelpers": true,
        "experimentalDecorators": true,
        "baseUrl": ".", // This must be specified if "paths" is.
        "paths": {
            "lib/*": [ "src/lib/*" ],
            "modules/*": [ "src/modules/*" ],
            "vendor/*": [ "src/vendor/*" ]
        },
        "typeRoots" : ["src/typings"]
    },
    "include": [
        "src/**/*.ts",
        "src/**/.*.ts", // TS ignores file names starting with dot by default
        "tests/**/*.ts",
        "tests/**/.*.ts"
    ]

die tsconfig des Hauptprojekts ( @croc/webclient ist das verknüpfte Paket):

    "extends": "./node_modules/@croc/webclient/tsconfig",
    "include": [
        "src/**/*.ts",
        "src/**/.*.ts",
        "node_modules/@croc/webclient/src/**/*.ts",
        "node_modules/@croc/webclient/src/**/.*.ts"
    ],
    "compilerOptions": {
      "baseUrl": ".",
      "typeRoots" : ["node_modules/@croc/webclient/src/typings"],
      "paths": {
        // map runtime paths to compile-time paths
        "lib/*": [ "node_modules/@croc/webclient/src/lib/*" ],
        "modules/*": [ "node_modules/@croc/webclient/src/modules/*" ],
        "vendor/*": [ "node_modules/@croc/webclient/src/vendor/*" ]
      }
    }

@ evil-shrike Kannst du dein Projekt auf ein einfaches Beispiel reduzieren, das das Problem demonstriert?

@mhegazy hier ist es
https://github.com/evil-shrike/typescript-npmlink-issue
in der Projektwurzel:

cd lib
npm link
cd ../main
npm link tstest-lib

dann in main :

npm run tsc

Hi @ evil-shrike, ich habe das Problem eingegrenzt auf:
lib / tsconfig.json

{
    "compilerOptions": {
        "typeRoots" : ["src/typings"]
    }
}

main / tsconfig.json

{
    "extends": "./node_modules/tstest-lib/tsconfig",
    "include": [
        "node_modules/tstest-lib/src/**/*.ts"
    ]
}

Also schließen wir am Ende beide ein (von tsc --listFiles ):

/main/node_modules/tstest-lib/src/typings/jquery/index.d.ts
/lib/src/typings/jquery/index.d.ts

Da node_modules von include und nicht von der Modulauflösung stammt, werden wir nicht realpath darauf nennen, sodass es sich um zwei verschiedene enthaltene Dateien handelt.
Es ist am besten, Ihre node_modules sowieso nicht einzuschließen und sie stattdessen separat zu kompilieren und wie jedes andere externe Paket zu importieren.

@ andy-ms
Das ist nicht einfach. Die referenzierte Bibliothek in meinem Fall hat viele Umgebungs-d.ts, die zum Beispiel globale Schnittstellen erweitern. Wie JQueryStatic:

interface JQueryStatic {
    cleanData (elems);
}

oder deklarieren Sie Präfixe für geladen (requirejs):

declare module "i18n!*" {
    //const m: { [key: string]: string };
    const m;
    export = m;
}

Dann werden sie irgendwo in der Quelle von lib verwendet:

const oldCleanData = $.cleanData;
$.cleanData = function (elems: JQuery) {
..
    oldCleanData(elems);
};

Wenn ein solches Modul (aus lib) irgendwo in main importiert wird, schlägt die Kompilierung fehl.

In der Quelle Ihrer Bibliothek sollten Sie die Anweisungen /// <reference types="" /> (oder /// <reference path="" /> ) verwenden, um sicherzustellen, dass die erforderlichen Eingaben beim Import Ihrer Bibliothek vorhanden sind. Auf diese Weise muss es nicht in "include" enthalten sein. Beim Import werden die referenzierten Typen automatisch zum Projekt hinzugefügt.

@ andy-ms danke, ich habe meine lib überarbeitet und jetzt wird ein projekt, in dem es npm-link-ed ist, gut kompiliert.

Ich bin mir nicht sicher, ob es sich um zu große Reproduktionen handelt, aber ich erhalte dasselbe aus einer Barebone-Installation von CLI mit Angular @ next und Typoskript @ next , die mit Observable<T> !== Observable<T> zu tun hat:

https://github.com/intellix/angular-cli-red
https://github.com/intellix/angular-cli-blue

Blau importiert und verwendet eine Komponente und einen Dienst von Rot

@intellix Können Sie ein Beispiel für Fehler erhalten, bei denen nur die Befehlszeile tsc wird? Schwer zu sagen, welche Version von Typoskript ng verwendet.

@ andy-ms Ich habe immer noch dieses Problem. Dies tritt bei mir auf, wenn ich versuche, die npm-Verbindung zwischen den von mir erstellten vscode -Erweiterungen zu verwenden. Sie alle importieren vscode was zu doppelten Bezeichnungsfehlern führt.
TS Version 2.7.0-dev.20171118

Bei mir hat es funktioniert, zum Beispiel "rxjs / *" einem bestimmten rxjs-Ordner innerhalb von node_modules im Pfadabschnitt der tsconfig-Datei zuzuordnen.
Jetzt funktioniert alles gut mit npm link.

Ich habe dies auch gesehen, als ich von einem Link zur Versionsaktualisierung zu einem Paket von symlinked zu non-symlinked gewechselt bin.

Siehe auch diese SO-Frage: https://stackoverflow.com/questions/38168581/observablet-is-not-a-class-derived-from-observablet

@dakaraphi @JoshuaKGoldberg Können Sie Anweisungen zur Reproduktion dieser Szenarien geben?

Mit dem neuen Verhalten sollten wir kein Paket einschließen, wenn wir bereits ein anderes Paket mit demselben "Versions" -Wert in package.json . Wenn Sie mehrere Installationen mit unterschiedlichen Versionen haben, erhalten Sie zwei verschiedene Kopien des Moduls. Dies könnte erklären, warum ein Versionsupdate dies unterbrechen würde, wenn nur eine von zwei Installationen betroffen wäre.

@ andy-ms Das Beispiel, das ich habe, sind die folgenden Repositorys:

  1. https://github.com/dakaraphi/vscode-extension-fold
  2. https://github.com/dakaraphi/vscode-extension-common

Ich verwende die lokale npm-Installation, um auf vscode-extension-common von vscode-extension-fold zu verweisen

Wenn Sie diese Repositorys auschecken, funktionieren sie derzeit, da ich eine Problemumgehung für die Pfadzuordnung in package.json von vscode-extension-fold . Wenn ich jedoch richtig verstehe, sollte ich diese Problemumgehung nicht benötigen.

@ Dakaraphi Danke! Es sieht so aus, als ob der Fehler darauf zurückzuführen ist, dass vscode.d.ts als globale Umgebungsdeklaration und nicht als externes Modul geschrieben wird. Ich habe Microsoft / vscode-extension-vscode # 90 erstellt.

Dies funktioniert bei mir immer noch nicht, wenn ich versuche, zwei Pakete zu verknüpfen, die jeweils von rxjs abhängig sind. Ich verwende [email protected] und [email protected] . Beide Pakete verwenden genau die gleiche Version. Hat jemand eine Problemumgehung dafür?

@SamVerschueren Können Sie spezifische Anweisungen zur Reproduktion des Fehlers geben? Testen Sie auch mit typescript@next .

@ andy-ms Ich werde sehen, was ich tun kann!

@ andy-ms Hier ist ein kleines Reproduktions-Repository https://github.com/SamVerschueren/ts-link-6496. Ich habe [email protected] , um dies zu reproduzieren.

  1. Installieren Sie beide Abhängigkeiten für mod-a und mod-b
  2. Kompilieren Sie mod-b mit yarn build
  3. Kompilieren Sie mod-a mit yarn build

Schritt 3 schlägt mit dem folgenden Fehler fehl

src/index.ts(7,15): error TS2345: Argument of type 'UnaryFunction<Observable<string>, Observable<string>>' is not assignable to parameter of type 'UnaryFunction<Observable<string>, Observable<string>>'.
  Types of parameters 'source' and 'source' are incompatible.
    Type 'Observable<string>' is not assignable to type 'Observable<string>'. Two different types with this name exist, but they are unrelated.
      Property 'buffer' is missing in type 'Observable<string>'.
src/index.ts(7,47): error TS7006: Parameter 'result' implicitly has an 'any' type.

Dieses Problem tritt immer noch mit [email protected] auf. Habe auch

Die Wurzel des Problems scheint zu sein, dass verknüpfte Pakete immer noch auf die Typdefinitionen in ihrem eigenen lokalen node_modules verweisen, anstatt die Typisierungen aus dem node_modules zu verwenden, mit dem sie verknüpft sind, wenn dies möglich ist. Das kombiniert mit der Tatsache, dass:

  1. Globale können nicht neu definiert werden

    • Dies führt dazu, dass sich der Compiler beschwert, wenn das Globale sowohl im node_modules des übergeordneten Projekts als auch im node_modules im verknüpften Paket definiert ist

  2. Klassen, die ansonsten identisch sind, können einander nicht zugewiesen werden

    • Dies führt dazu, dass sich der Compiler beschwert, wenn er versucht, eine Variable, deren Typ eine Klasse aus dem node_modules des übergeordneten Projekts ist, einem Wert zuzuweisen, der vom verknüpften Paket zurückgegeben wird, dessen Typ in seinem eigenen node_modules

Ich konnte dieses Problem mit der Konfigurationsvariablen paths umgehen. Für Module, deren Definitionen von @types/* , wie hier vorgeschlagen, können Sie einfach Folgendes verwenden:

"paths": {
  "*": ["node_modules/@types/*", "*"]
}

Wenn Sie auf dieses Problem mit einem Paket stoßen, das mit Typdefinitionen geliefert wird, die Klassen oder Globale definieren, müssen Sie diese manuell hinzufügen. Zum Beispiel rxjs :

"paths": {
  "rxjs": ["node_modules/rxjs"],
  "rxjs/*": ["node_modules/rxjs/*"]
}

Ich habe auch Probleme mit Symlinks, wenn ich ein lokales Paket mit TS 2.8.3 hinzufüge:

},
"devDependencies": {
    "@types/MyLib": "file:../MyLib/bin/npm/@types"
},

Seit v3 installiert npm diese offenbar mit Symlinks, anstatt die Dateien zu kopieren.

Wenn ich jedoch versuche zu kompilieren, sieht der Compiler die verknüpfte Definitionsdatei als zwei separate und widersprüchliche Dateien:

node_modules\@types\MyLib\index.d.ts(3,11): error TS2300: Duplicate identifier 'Foo'.
C:/MySolution/MyLib/bin/npm/@types/index.d.ts(3,11): error TS2300: Duplicate identifier 'Foo'.

Wenn ich die Dateien stattdessen manuell kopiere, funktioniert es wie erwartet. Ich kann das umgehen, indem ich typeRoots: ["./node_modules/**/"]

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

Roam-Cooper picture Roam-Cooper  ·  3Kommentare

weswigham picture weswigham  ·  3Kommentare

DanielRosenwasser picture DanielRosenwasser  ·  3Kommentare

wmaurer picture wmaurer  ·  3Kommentare

Antony-Jones picture Antony-Jones  ·  3Kommentare