-
Notifications
You must be signed in to change notification settings - Fork 109
Can't emit types into same namespace as values #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Rado suggested we might be able to do some trickery like interface ts_Foo { ... }
type Foo = ts_Foo; and then when But a local experiment found that the place where we emit types gets the type after aliasing has been resolved. |
Summary: When we're not using Closure types, we don't need to emit Closure interfaces. Avoids #146, unblocks the tsickle sync into Google. Reviewers: rkirov Reviewed By: rkirov Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D120
Idea: always emit TS interfaces into a mangled Closure name, like Problem 1. This breaks for builtin types like "Array" and "Object". However, emitting those interfaces verbatim as we do right now is saying that they are equivalent between TS and Closure's definitions of those terms. I think this is fine for Array and Object, but it might not be fine for more complex types. I think a whitelist (perhaps derived from lib.d.ts) of types that are considered compatible might get us pretty far. Problem 2. Mangling names breaks interop with Closure code. E.g. a function returns a I think collisions are unlikely enough that this approach is not gonna work. I will leave it here as a rejected proposal. |
Idea 2: locally detect when there is a naming conflict and just dodge it there. It might be possible to look up, given a symbol, whether that symbol represents both a type and a name in a TS file. When that scenario occurs, rewrite all the instances of the type to something else when emitting. The hard part then is making the dependent code recognize it. Within a compilation unit perhaps we can just construct a map by doing one pass over all the files first before emitting any. Across compilation units, we can stash the mangled name into a comment and extract it from the docstring in the d.ts file(!). This might actually work. I'm gonna prototype it now. |
It took me quite a while to figure out how to find the conflicting symbols, but it seems to basically work in a single file test case. Next, I'll attempt a multi-file case. Multi-file is hard because you can write: import {Foo} from './bar'; and we need to figure out that it is import {Foo, tsickle_Foo} from './bar'; (where |
This works! At least in my test case -- it generates these funky names and adds extra exports/imports where necessary. But then it fails due to #112 . I need to fix that first before I can fix this. |
Another simpler idea is: when there's a type/value conflict, just omit bringing the type into the Closure and treat it as {?}. That "solves" this problem at the cost of slightly weaker typing. I still think I can implement the renaming thing but it might be worth checking how much it helps because it adds a lot of complexity. |
We now think that #146 (comment) can work. |
is legal TS. But if you translate the
interface
into Closure directly it goes into the single (value) namespace and the two definitions conflict.It's easy enough to just emit interfaces under some mangled name in Closure, e.g.
but then you need to fix every reference to that interface in any Closure type, while at the same time leaving other references (e.g.
Array
) alone. And you need to figure out how to import it across files (if a file doesimport {Foo} from bar
, you'd need to change it toimport {Foo, tsickle_Foo} from bar
).The text was updated successfully, but these errors were encountered: