electricessence / TypeScript.NET

A JavaScript-Friendly .NET Based TypeScript Library (Moved)
https://github.com/electricessence/TypeScript.NET-Core
Other
251 stars 36 forks source link

import from TypeScript.NET breaks compilation #67

Closed lukos closed 6 years ago

lukos commented 6 years ago

This is likely to be a newb problem that needs some documentation, but I have an interface that is referenced in another interface within the same namespace (in separate files):

IBusinessLayer.ts:

/// <reference path="IClientUtilities.ts" />

namespace SharedBusinessLayer {
    export interface IBusinessLayer {
             ClientUtilities: IClientUtilities;
    }
}

IClientUtilities.ts

import Dictionary from "typescript-dotnet-umd/System/Collections/Dictionaries/Dictionary"

namespace SharedBusinessLayer {
    export interface IClientUtilities {
    }   
}

BUT, when I include the import line into the top of IClientUtilities (to return from a property that is not yet declared), the ts build fails for IBusinessLayer "error TS2304: Cannot find name 'IClientUtilities'". If I remove the import line, the build succeeds.

I'm guessing that the import is screwing with my namespaces but I don't know how to fix it.

electricessence commented 6 years ago

I don't believe this has anything to do with TypeScript.NET. I think it is due to mixing namespaces with modules.

https://www.typescriptlang.org/docs/handbook/namespaces.html This information might be obsolete as it's not really using modules as you are attempting.

You might notice that TypeScript.NET has ZERO namespaces. That's because the idea behind 'modules' is that namespaces simply don't need to exist.

Also... Interfaces are a funny thing. They don't need to be part of a real module. You can define an exported namespace by itself within a *d.ts file and it won't need to compile. Interfaces don't generate real JS code.

lukos commented 6 years ago

Thanks for the reply. It is very possible that the problem you described is correct although I don't understand how it breaks compilation just by importing the type. I would understand if I was trying to use the Dictionary type and it couldn't resolve properly. I believe there are changes in later typescript versions where "internal modules" are now namespaces so I will have to investigate some more, it will be a shame if I can't use your great library.

electricessence commented 6 years ago

If you notice the examples in the link, they are using old-style ///<reference> tags instead of modules. These are not normally 'mixed' with modules.

If you are trying to build a monolith library then you can do what you're thinking, but you would need to throw out modules all together...

A long time ago, TypeScript.NET would have worked with namespaces, but now TypeScript.NET is all modules. If you are going to use it, try it without namespaces.

In a modular world, "think modules". Folders can be your namespaces. But the idea behind modules is that namespaces simply aren't necessary. You can import a specific 'module' and name it however you want without concern for collision.

lukos commented 6 years ago

OK. So I removed all my namespaces and am trying to use Enumerable and the TypeScript compiler is erroring. The errors are:

C:/Users/luke/source/repos/nodespeedtest/node_modules/typescript-dotnet-umd/System.Linq/Linq.d.ts(16,22): error TS2420:
Class 'InfiniteLinqEnumerable<T>' incorrectly implements interface 'IInfiniteEnumerable<T>'.
  Types of property 'doAction' are incompatible.
    Type '{ (action: ActionWithIndex<T> | PredicateWithIndex<T> | SelectorWithIndex<T, number> | SelectorWi...' is not a
ssignable to type '{ (action: ActionWithIndex<T> | PredicateWithIndex<T> | SelectorWithIndex<T, number> | SelectorWi...'
. Two different types with this name exist, but they are unrelated.
      Type 'InfiniteLinqEnumerable<T>' is not assignable to type 'IInfiniteEnumerable<T>'.
        Types of property 'doAction' are incompatible.
          Type '{ (action: ActionWithIndex<T> | PredicateWithIndex<T> | SelectorWithIndex<T, number> | SelectorWi...' is
 not assignable to type '{ (action: ActionWithIndex<T> | PredicateWithIndex<T> | SelectorWithIndex<T, number> | Selector
Wi...'. Two different types with this name exist, but they are unrelated.
            Type 'InfiniteLinqEnumerable<T>' is not assignable to type 'ILinqEnumerable<T>'.
              Property 'skipWhile' is missing in type 'InfiniteLinqEnumerable<T>'.

There are also two other errors related to skip(), which are similar and related to LinqEnumerable is not assignable to type 'ILinqEnumerable

I'm not sure if it is related but if I ignore these errors and attempt to run the node server, when I call the following code I get another error. I'm not sure whether the compiler error is caused by a coding error or whether the runtime error is related to a problem with the typescript-dotnet package code?

import Enumerable from 'typescript-dotnet-umd/System.Linq/Linq';

// etc

var datahash: string;
let myEnumerable = Enumerable.from(user.Claims);       // <-- Error is here
if (user.Claims != null && myEnumerable.any(c=>c.Type == "datahash"))
{
    datahash = myEnumerable.where(c => c.Type == "datahash").firstOrDefault().Value;
}

User.ts:

import List from "typescript-dotnet-umd/System/Collections/List";
import { Claim } from './Claim';

export class User {
    private claims: List<Claim>;

    get Claims(): List<Claim> {
        return this.claims;
    }

    set Claims(claims: List<Claim>) {
        this.claims = claims;
    }
}

error: UnsupportedEnumerableException: Unsupported enumerable.

electricessence commented 6 years ago

Ok. I will look into this. I've had to do some refactoring previously to get the interfaces to compile properly with the Linq library. Make sure you have the latest version. I will update within 24 hours.

electricessence commented 6 years ago

So this may be a new TS version problem. It's an absolute nightmare upgrading past TS 2.3.2. I've been waiting for the compiler to stop running out of memory for me to upgrade. I'll keep trying but just to report in. My current build not only builds and runs perfectly without error, I did test Enumerable.from(list) without incident also.

Side note, you can do this as well:

var e = Enumerable(list); // same as Enumerable.from(list);

In a node (commonjs) environment:

let datahash  = list.linq.where(x=>x.Type=="datahash").firstOrDefault().Value;

in other environments

(AMD loaded or non-commonJS):

let datahash;
list.linqAsync(e=>{
   datahash = e.where(x=>x.Type=="datahash").firstOrDefault().Value;
});

And you can:

let isLinqReady = false;
let linq = list.linqAsync(e=>{isLinqReady=true;});
////////////////// Later on....
if(!linq && isLinqReady) linq = list.linq;
let datahash  = linq.where(x=>x.Type=="datahash").firstOrDefault().Value;

You might be asking, why not include it by default? The reason is modularity. The Linq module is HUGE and some people may not use it. So especially for web, it's not included by default.

Here's the helper code implementation: https://github.com/electricessence/TypeScript.NET/blob/master/source/System/Collections/CollectionBase.ts#L425-L496

electricessence commented 6 years ago

v4.9.9 released to npm... Should fix the issues you encountered. It now compiles with more recent TS versions like 2.5.3 and even 2.7.0-dev. But I kept the required version at ^2.3.2 because I still encounter a heap memory error when trying to compile my dist packages. https://github.com/Microsoft/TypeScript/issues/18411

Please try the latest version and tell me if its working for you. I'm guessing you have 2.5.3 and it is a bit more strict and found inconsistencies with the Enumerable.d.ts file and Linq.ts.

Thanks for bringing this to my attention.

electricessence commented 6 years ago

@lukos did you get it working?