Skip to content
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

wrong type ordering generated by tsc? #60044

Closed
khteh opened this issue Sep 24, 2024 · 9 comments
Closed

wrong type ordering generated by tsc? #60044

khteh opened this issue Sep 24, 2024 · 9 comments
Labels
Unactionable There isn't something we can do with this issue

Comments

@khteh
Copy link

khteh commented Sep 24, 2024

🔎 Search Terms

tsc node.js

🕗 Version & Regression Information

  • This changed between versions ______ and _______
  • This changed in commit or PR _______
  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________
  • I was unable to test this on prior versions because _______

⏯ Playground Link

https://github.com/khteh/Node.JSRestAPI

💻 Code

State.ts:

import { ILogger, LogLevels } from "../../Interfaces/ILogger.js";
import { injectable, inject } from "inversify";
import { LoggerTypes } from '../../types.js';
import StateContext from "./StateContext.js";
import { StatusEnum, StatusColors } from "./StateEnums.js";

export default abstract class State {
    protected readonly _logger: ILogger;
    protected readonly _name: StatusEnum;
    protected readonly _colour: string;
    protected readonly _context: StateContext;
    protected constructor(@inject(LoggerTypes.ILogger) logger: ILogger, name: StatusEnum, context: StateContext) {
        this._logger = logger;
        this._name = name;
        this._context = context;
        this._colour = StatusColors[this._name] || StatusColors[StatusEnum.NEW]
    }
    public abstract handle (): void;
    public Name (): StatusEnum { return this._name }
}

StateContext.ts:

import { ILogger, LogLevels } from "../../Interfaces/ILogger.js";
import { injectable, inject } from "inversify";
import { LoggerTypes } from '../../types.js';
import State from "./State.js";
import { StatusEnum } from "./StateEnums.js";

export default class StateContext {
    private readonly _logger: ILogger;
    private _state?: State;
    public constructor(@inject(LoggerTypes.ILogger) logger: ILogger, state?: State) {
        this._logger = logger;
        this._state = state;
    }
    public async handle () {
        // Do operation
        if (this._state)
            this._state.handle();
    }
    public async ChangeState (state?: State) {
        this._logger.Log(LogLevels.debug, `Current state ${this._state?.Name()}`);
        this._state = state;
        this._logger.Log(LogLevels.debug, `New state ${this._state?.Name()}`);
    }
    public State (): StatusEnum | null {
        return this._state ? this._state.Name() : null;
    }
}

Generated .js code:

let State = class State {
    _logger;
    _name;
    _colour;
    _context;
    constructor(logger, name, context) {
        this._logger = logger;
        this._name = name;
        this._context = context;
        this._colour = StatusColors[this._name] || StatusColors[StatusEnum.NEW];
    }
    Name() { return this._name; }
};
State = __decorate([
    __param(0, inject(LoggerTypes.ILogger)),
    __metadata("design:paramtypes", [Object, String, StateContext]) // XXX Error here!!!
], State);
var State$1 = State;

let StateContext = class StateContext {
    _logger;
    _state;
    constructor(logger, state) {
        this._logger = logger;
        this._state = state;
    }
    async handle() {
        // Do operation
        if (this._state)
            this._state.handle();
    }
    async ChangeState(state) {
        this._logger.Log(LogLevels.debug, `Current state ${this._state?.Name()}`);
        this._state = state;
        this._logger.Log(LogLevels.debug, `New state ${this._state?.Name()}`);
    }
    State() {
        return this._state ? this._state.Name() : null;
    }
};
StateContext = __decorate([
    __param(0, inject(LoggerTypes.ILogger)),
    __metadata("design:paramtypes", [Object, State$1])
], StateContext);

🙁 Actual behavior

$ n run start

> [email protected] start
> export NODE_ENV=development&& node build/src/webapi/server.js

file:///usr/src/Node.JSRestAPI/src/webapi.core/build/index.js:646
    __metadata("design:paramtypes", [Object, String, StateContext])
                                                     ^

ReferenceError: Cannot access 'StateContext' before initialization
    at file:///usr/src/Node.JSRestAPI/src/webapi.core/build/index.js:646:54
    at ModuleJob.run (node:internal/modules/esm/module_job:262:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:483:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5)

Node.js v22.9.0

🙂 Expected behavior

No runtime error, duh!

Additional information about the issue

No response

@MartinJohns
Copy link
Contributor

Duplicate of #27519. The error is different, the cause is the same.

@khteh
Copy link
Author

khteh commented Sep 24, 2024

What's the solution?

@MartinJohns
Copy link
Contributor

I think it should work to use a method instead of the object directly, e.g. : context: () => StateContext instead of context: StateContext.

@khteh
Copy link
Author

khteh commented Sep 24, 2024

build error:

Domain/States/ApprovedState.ts:9:44 - error TS2345: Argument of type 'StateContext' is not assignable to parameter of type '() => StateContext'.
  Type 'StateContext' provides no match for the signature '(): StateContext'.

9         super(logger, StatusEnum.APPROVED, context);
                                             ~~~~~~~

Domain/States/NewState.ts:11:39 - error TS2345: Argument of type 'StateContext' is not assignable to parameter of type '() => StateContext'.
  Type 'StateContext' provides no match for the signature '(): StateContext'.

11         super(logger, StatusEnum.NEW, context);
                                         ~~~~~~~

Domain/States/QuotedState.ts:13:42 - error TS2345: Argument of type 'StateContext' is not assignable to parameter of type '() => StateContext'.
  Type 'StateContext' provides no match for the signature '(): StateContext'.

13         super(logger, StatusEnum.QUOTED, context);
                                            ~~~~~~~

Domain/States/RejectedState.ts:10:44 - error TS2345: Argument of type 'StateContext' is not assignable to parameter of type '() => StateContext'.
  Type 'StateContext' provides no match for the signature '(): StateContext'.

10         super(logger, StatusEnum.REJECTED, context);
                                              ~~~~~~~

Domain/States/State.ts:15:25 - error TS2322: Type '() => StateContext' is not assignable to type 'StateContext'.

15         this._context = context;
                           ~~~~~~~

  Domain/States/State.ts:15:25
    15         this._context = context;
                               ~~~~~~~
    Did you mean to call this expression?


Found 5 errors in 5 files.

Errors  Files
     1  Domain/States/ApprovedState.ts:9
     1  Domain/States/NewState.ts:11
     1  Domain/States/QuotedState.ts:13
     1  Domain/States/RejectedState.ts:10
     1  Domain/States/State.ts:15
npm error Lifecycle script `build` failed with error:
npm error code 1
npm error path /usr/src/Node.JSRestAPI/src/webapi.core
npm error workspace [email protected]
npm error location /usr/src/Node.JSRestAPI/src/webapi.core
npm error command failed
npm error command sh -c tsc --project tsconfig.json && npm run rollup
ERROR: "build_core" exited with 1.

@MartinJohns
Copy link
Contributor

These errors are quite clear and an issue in your code / with the library you use. It should be obvious that you can't just change the parameter to () => Whatever, and then use it in-place where Whatever type is expected.

@khteh
Copy link
Author

khteh commented Sep 24, 2024

Type '() => StateContext' is not assignable to type StateContext error shown by intellisense:

import { ILogger, LogLevels } from "../../Interfaces/ILogger.js";
import { injectable, inject } from "inversify";
import { LoggerTypes } from '../../types.js';
import StateContext from "./StateContext.js";
import { StatusEnum, StatusColors } from "./StateEnums.js";

export default abstract class State {
    protected readonly _logger: ILogger;
    protected readonly _name: StatusEnum;
    protected readonly _colour: string;
    protected readonly _context: StateContext;
    protected constructor(@inject(LoggerTypes.ILogger) logger: ILogger, name: StatusEnum, context: () => StateContext) {
        this._logger = logger;
        this._name = name;
        this._context = context; // XXX: Intellisense says Type '() => StateContext' is not assignable to type StateContext
        this._colour = StatusColors[this._name] || StatusColors[StatusEnum.NEW]
    }
    public abstract handle (): void;
    public Name (): StatusEnum { return this._name }
}

@MartinJohns
Copy link
Contributor

Type '() => StateContext' is not assignable to type StateContext error shown by intellisense:

Yes, hence I wrote:

It should be obvious that you can't just change the parameter to () => Whatever, and then use it in-place where Whatever type is expected.

You need to adjust your code accordingly.

@khteh
Copy link
Author

khteh commented Sep 24, 2024

I am a noob in this. Can you enlighten me on this?

@RyanCavanaugh RyanCavanaugh added the Unactionable There isn't something we can do with this issue label Sep 24, 2024
@RyanCavanaugh
Copy link
Member

It looks like this is a question rather than a bug report. This issue tracker is for tracking bugs and active work on TypeScript itself, rather than a general forum for programmers using TypeScript to get help or ask questions.

You can ask questions on sites like Stack Overflow. We are not able to provide one-on-one support on the issue tracker. Please read the issue template carefully - it has important information on what kinds of reports can be acted on here, as well as links to useful TypeScript resources. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Unactionable There isn't something we can do with this issue
Projects
None yet
Development

No branches or pull requests

3 participants