-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
3.8 RC Regression? "Individual declarations in merged declaration" #36684
Comments
@andrewbranch I thought this was a break in 3.7 |
@DanielRosenwasser it looks like #31231 simply failed to handle the combination of namespace import + type alias... 😱 |
I guess we accidentally fixed that case, which we had previously accidentally left unfixed, sometime after the beta? Possibly with #36237? Sorry @DanielRosenwasser, I should have recognized #36237 as a breaking change 😕 |
@andrewbranch @DanielRosenwasser this is working as intended? So, I'll need to change my code to upgrade to 3.8+? |
Yes, I believe so. It's something I wish we could've communicated sooner, but the code never should have compiled. |
Okay, thanks. For the record, this pattern can be really useful in terms of exposing a type + a set of functions on that type. You can do this with an explicit namespace in a file, but I thought that was not encouraged anymore. Like this: export type Greeting = {greet: string}
export namespace Greeting {
export function hello(input: Greeting) {
console.log(input.greet)
}
} These seem isomorphic and it seems weird to allow one and not the other. |
@garrettm the issue isn’t with what will merge as exports, it’s that imports are never allowed to merge with local declarations. You could rewrite your original example as // use.ts
import * as ns from './ns'
export type Greeting = ns.Type
export { ns as Greeting } and that would be fine. |
@andrewbranch thanks! That worked. |
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
@garrettm @andrewbranch Do you have an example of that rewritten form working in the wild? It seems like the syntax is fine but I can't actually import the value of // example-1.ts
import { Greeting } from "./use.ts";
let greeting: Greeting = { greet: "hi" };
Greeting.hello(greeting);
// 'Greeting' only refers to a type, but is being used as a value here. Oddly enough, it seems to work when I import the entire module with a wildcard. // example-2.ts
import * as Use from "./use.ts";
let greeting: Use.Greeting = { greet: "hi" };
Use.Greeting.hello(greeting); I had been using the following workaround: // use.ts
import * as ns from "./ns";
export const Greeting = ns;
export type Greeting = ns.Greeting; But I've just discovered that it breaks tree shaking for Rollup (and presumably other bundlers). Anything that imports The important difference seems to be that tree shaking only works when the values are re-exported directly. // works with tree shaking, not with typescript
export { ns as Greeting };
// works with typescript, not with tree shaking
export const Greeting = ns.Greeting; This is possibly a separate issue to the original report, but I'm not sure. Here's a repro for anyone who can dig further than I can https://github.com/danprince/ts-export-types-bug |
Hmm curious, I'm not having any luck with the latest non-beta TSC with @andrewbranch's workaround anymore either. Maybe I had a slightly different setup, or maybe this changed in a 3.8.x? Your workaround does work for me @danprince It would be nice if this was more ergonomic in general in typescript |
One downside of @danprince's workaround is that you can't export types from the namespace, you get this error when you try to use it: |
@danprince sorry I missed your comment earlier; that looks like it’s probably a bug. The
You’re seeing neither of those, which I’m pretty confident is wrong. |
It does seem like this behavior goes all the way back to TypeScript 1.x though, so I’m not sure it’s a candidate for a last-minute 3.9 fix 😄 |
Something that makes this type of thing easy to do would be super appreciated, from this user's perspective :) I haven't been able to find a good workaround for this at the moment |
Hey @andrewbranch! Thanks for clarifying here. Is this behaviour going to be considered for a post 3.9 release? Spending a lot of time writing |
It’s definitely not going to be included in a 3.9.x release, as the window for anything besides critical fixes closed a while ago. But I’m pretty sure the “bug” here is that we don’t give an error sooner: export type Greeting = {};
export { ns as Greeting }; These two exports shouldn’t be allowed to coexist. In a way, it looks like they already don’t coexist because the alias meaning is unreferenceable from an import, but we should be giving you an error here on the exports. So I don’t think we’re really looking at any work that will give you the results you’re looking for. If it’s important to you, you should open a new issue, but I’d suggest including some real-world code that demonstrates why this is important. From my perspective here, it looks a little bit like an aesthetic problem that a slight reorganization of file structure or a slight reimagining of names would solve, and it’s hard to understand why it matters with examples like |
@andrewbranch here's a slightly more real code example that's basically a real world example with details stripped out and trimmed down a lot for length. Users of this file want to
// animal.ts
export type Cat = {type: 'cat', remainingLives: string}
export type Dog = {type: 'dog', breed: string}
export type Animal = Cat | Dog
export function greet(animal: Animal) {
switch (animal.type) {
case 'cat': return 'meow'
case 'dog': return 'bark'
}
}
export function remainingLives(animal: Animal) {
switch (animal.type) {
case 'cat': return animal.remainingLives
case 'dog': return undefined
}
}
export function isCat(animal: Animal): animal is Cat {
return animal.type === 'cat'
} |
@andrewbranch I can also confirm my codebase is littered with
Every single one of these files is imported like ...which means I write |
TypeScript Version: 3.8.1-rc and nightly (3.8.0-dev.20200207)
Search Terms:
Individual declarations in merged declaration
Code
Two files:
Expected behavior:
Expected that this compiles and users can refer to Greeting as both the type
{greet: string}
and the namespace of functions/data (justhello
in this case). In versions3.7.5
and3.8.0-beta
, this was OK.Actual behavior:
3.8.1-rc and current nightly produce these errors:
The text was updated successfully, but these errors were encountered: