Skip to content

Resolved type depends on the import order if the aliased type is created by "export { A as B }" #55761

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

Closed
yifanwww opened this issue Sep 16, 2023 · 5 comments
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@yifanwww
Copy link

πŸ”Ž Search Terms

enum alias export

πŸ•— Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about enum

I tested these versions:

  • 5.2.2
  • 5.1.6
  • 5.0.4
  • 4.9.5
  • 4.8.4
  • 4.7.4
  • 4.6.4
  • 4.5.5

⏯ Playground Link

No response

πŸ’» Code

// enum.ts

export enum Foo {
    VALUE = 'value',
}

export { Foo as Bar };

// main-1.ts

import { Bar, Foo } from './enum';

const a = Bar.VALUE;
const b = Foo.VALUE;

// main-2.ts

import { Foo, Bar } from './enum';

const a = Bar.VALUE;
const b = Foo.VALUE;

πŸ™ Actual behavior

The inferred types of a and b in main-1.ts file are:

  • a: Bar.VALUE
  • b: Bar.VALUE

The inferred types of a and b in main-2.ts file are:

  • a: Foo.VALUE
  • b: Foo.VALUE

I made two files main-1.ts and main-2.ts to show that how the import order of enum changes the inferred types.

πŸ™‚ Expected behavior

I think there're two accepted bahaviors:

no.1

The inferred types should be:

  • main-1.ts
    • a: Foo.VALUE
    • b: Foo.VALUE
  • main-2.ts
    • a: Foo.VALUE
    • b: Foo.VALUE

no.2

The inferred types should be:

  • main-1.ts
    • a: Bar.VALUE
    • b: Foo.VALUE
  • main-2.ts
    • a: Bar.VALUE
    • b: Foo.VALUE

So in the code, Foo is the original enum and Bar is an alias of it.
I think we can accept that typescript infers a var assigned by Bar.VALUE to be Foo.VALUE because it's easy for developers to check the type of Bar and find that it's an alias of Foo. But I don't think it's good for typescript to infer a var assigned by Foo.VALUE to be Bar.VALUE, because if we assign the original enum to a variable directly, then the inferred type shouldn't be the aliased enum.

Additional information about the issue

No response

@MartinJohns
Copy link
Contributor

MartinJohns commented Sep 16, 2023

Afaik this is intentionally done for performance reasons. When multiple identifiers refer to the same type, then only the first type will be used. You have the same "issue" with type aliases: Playground link

Related: #31940

@yifanwww
Copy link
Author

yifanwww commented Sep 16, 2023

@MartinJohns By checking the difference, I noticed that they are not exactly the same problem.

You could write

// type.ts
export type FooType = {
    value: string;
};

export type AliasFooType = FooType;

export type BarType = {
    value: string;
};

export type { BarType as AliasBarType };

then use them in main.ts

// main.ts
import { AliasBarType, AliasFooType, BarType, FooType } from './type';

const a: FooType = { value: 'hello' };
const b: AliasFooType = { value: 'hello' };

const c: BarType = { value: 'hello' };
const d: AliasBarType = { value: 'hello' };

The inferred types are (by hovering mouse over the variable):

  • a: FooType
  • b: FooType
  • c: AliasBarType
  • d: AliasBarType

So there are two ways to make an alias and the second way seems to behave differently from the first way (I don't know the term so...):

  1. type alias: type B = A
  2. export alias: export { A as B }

If we are using "type alias" the alias type will possibly be resolve to the original type (we can use type B = A & {} to avoid it).
But if we are using "export alias", the resolved type will depend on the import order of the original type and aliased type.

For Enum, sadly we can only use "export alias" to create a aliased enum. If there're other ways to alias an enum pls let me know.

@yifanwww yifanwww changed the title Wrong inferred enum type when importing the original enum and an aliased enum Resolved type depends on the import order if the aliased type are created by "export { A as B }" Sep 16, 2023
@yifanwww yifanwww changed the title Resolved type depends on the import order if the aliased type are created by "export { A as B }" Resolved type depends on the import order if the aliased type is created by "export { A as B }" Sep 16, 2023
@MartinJohns
Copy link
Contributor

For Enum, sadly we can only use "export alias" to create a aliased enum. If there're other ways to alias an enum pls let me know.

export type Bar = Foo;
export const Bar = Foo;

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Sep 18, 2023
@yifanwww
Copy link
Author

export type Bar = Foo;
export const Bar = Foo;

Ok.. though I don't like the style but at least it works and I don't see any issues with it.

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Sep 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

4 participants