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

Update typescript compiler options #1311

Merged
merged 38 commits into from
Oct 7, 2021

Conversation

notaphplover
Copy link
Member

@notaphplover notaphplover commented Apr 18, 2021

Description

This PR aims to update Typescript version and add strict compiler options

Related Issue

#1222, #1271

Motivation and Context

We should try to use Typescript strict options in our project. This would help us to detect some typing issues such as #1222, which would have been detected.

How Has This Been Tested?

  • All tests passes successfully

Types of changes

  • Updated docs / Refactor code / Added a tests case (non-breaking change)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have updated the changelog.

package.json Outdated
@@ -71,7 +71,7 @@
"ts-node": "9.1.1",
"tsify": "^5.0.2",
"tslint": "6.1.3",
"typescript": "4.1.3",
"typescript": "^4.2.4",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typescript creates false minor versions, we should ensure we are using the right version

Suggested change
"typescript": "^4.2.4",
"typescript": "4.2.4",

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree

Dragos Podaru and others added 4 commits May 1, 2021 16:48
@PodaruDragos
Copy link
Member

@tonyhallett @notaphplover I really want to get this merged eventually. Things at this moment should be correct for building but tests are failing and I really don't know what's happening there. Maybe some of you can have a second opinion on this.

@tonyhallett
Copy link
Contributor

@PodaruDragos I am busy finishing a project at the moment. Might get the chance to take a look tomorrow or Thursday

@PodaruDragos
Copy link
Member

@PodaruDragos I am busy finishing a project at the moment. Might get the chance to take a look tomorrow or Thursday

no worries, take your time

@PodaruDragos PodaruDragos mentioned this pull request Aug 23, 2021
10 tasks
@PodaruDragos
Copy link
Member

PodaruDragos commented Aug 25, 2021

@tonyhallett @notaphplover I've kept this branch up to date. There are 2 issues when running test and 1 issue when running test:browser and build.

Can you also take a look at what's going on there maybe you have a clearer picture on how to solve those issues.
Then I think we can merge this safely and focus on the binding-abstractions with stricter typescript.

@tonyhallett
Copy link
Contributor

Looking at it now

@tonyhallett
Copy link
Contributor

image

Rectified with change to

    public toAutoNamedFactory<T2>(serviceIdentifier: interfaces.ServiceIdentifier<T2>): BindingWhenOnSyntax<T> {
        this._binding.type = BindingTypeEnum.Factory;
        this._binding.factory = (context) => {
            return (named: unknown) => context.container.getNamed<T2>(serviceIdentifier, named as string);
        };
        return new BindingWhenOnSyntax<T>(this._binding);
    }

@tonyhallett
Copy link
Contributor

tonyhallett commented Aug 25, 2021

I would also say that the pull by @leonardssh has introduced an issue in the typings.

export type Factory<T, U extends unknown[] = unknown[]> = (...args: U) => (((...args: U) => T) | T);

When

 (...args: U) => (...args: U) => T

Why should the second arguments be the same as the first ?

This error can be seen in

container.bind<interfaces.Factory<Engine>>("Factory<Engine>").toFactory<Engine>((context: interfaces.Context) =>

        container.bind<interfaces.Factory<Engine>>("Factory<Engine>").toFactory<Engine>((context: interfaces.Context) =>
            (theNamed: string) => (displacement: number) => {
                const theEngine = context.container.getNamed<Engine>("Engine", theNamed);
                theEngine.displacement = displacement;
                return theEngine;
            });

Also note that because of unknown you have to provide the second generic to 'toFactory' ( or have unknown parameters )

@tonyhallett
Copy link
Contributor

After clearing the issue identified by ci build I then noticed in my error list that there were 50ish other errors with many that are not pertaining to 'update typescript compiler options' but are a result of the merge and the fix leaving the code in this present state.

Please resolve resolver.test.ts and get Factory/FactoryCreator sorted.
Note that Provider/ProviderCreator have not changed.

export type Provider<T> = (...args: any[]) => (((...args: any[]) => Promise<T>) | Promise<T>);

Then I will help look at the decorator issues and any strange ci browser test issue that may present itself.

@PodaruDragos
Copy link
Member

@tonyhallett checked the branch right now, i don't have any issues but the one already mentioned

@PodaruDragos
Copy link
Member

I also formatted the code to have 2 spaces all over the place.. The 4 and 2 spaces randomly was really freaking me out.
This was also agreed with Dan when we eventually do finish this and move to eslint that we should use 2 spaces for formatting.

@tonyhallett hope that didn't cause you any discomfort.

@tonyhallett
Copy link
Contributor

checked the branch right now, i don't have any issues but the one already mentioned

I will check to see what stupid mistake I made - apologies in advance

@tonyhallett
Copy link
Contributor

@PodaruDragos
Please can you tell me what comment of mine you deleted

@PodaruDragos
Copy link
Member

@PodaruDragos
Please can you tell me what comment of mine you deleted

yeah sorry , the one with cast to number that I modified to be as string.

@tonyhallett
Copy link
Contributor

yeah sorry , the one with cast to number that I modified to be as string.

Ok 😉

@@ -58,7 +58,7 @@ The signature of a provider look as follows:

```ts
interface Provider<T> extends NewableFunction {
(...args: any[]): (((...args: any[]) => Promise<T>) | Promise<T>);
(...args: unknown[]): (((...args: unknown[]) => Promise<T>) | Promise<T>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we replace the interface with the type that we are exporting ? Similarly with ProviderCreator.

export type Factory<T, U extends unknown[] = unknown[], V extends unknown[] = unknown[]> = (...args: U) => (((...args: V) => T) | T);
export type SimpleFactory<T, U extends unknown[] = unknown[]> = (...args: U) => T;

export type MultiFactory<T, U extends unknown[] = unknown[], V extends unknown[] = unknown[]> = (...args: U) => SimpleFactory<T,V>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PodaruDragos
Helper types added. We need a better name for MultiFactory

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need some of the markdown files to be generated from actual tests so that required updates to markdown automatically occur when we change types. Will also prevent incorrect typing that I encountered when adding new functionality.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about CompoundFactory ?
I also think MultiFactory is fine

@PodaruDragos
Copy link
Member

Please revert / adjust accordingly
getDependencies
getBaseClassDependencyCount
listRegisteredBindingsForServiceIdentifier

this should also be done

@tonyhallett
Copy link
Contributor

Please revert / adjust accordingly
getDependencies
getBaseClassDependencyCount
listRegisteredBindingsForServiceIdentifier

this should also be done

You did two of them, I did the other.

@PodaruDragos
Copy link
Member

cntnr should be cast to object with _bindingDictionary

why are we not making this public ?

@PodaruDragos
Copy link
Member

You did two of them, I did the other.

oh sorry, I must have slipped that

@tonyhallett
Copy link
Contributor

why are we not making this public ?

We want to control access through fluent syntax

@PodaruDragos
Copy link
Member

also we have a lot of tests where we do this

// cast to any to be able to access private props. maybe we could consider making those public aswell, since we are not really using private methods. or change everything to be private methods ex: #example = () => void

@tonyhallett
Copy link
Contributor

also we have a lot of tests where we do this

// cast to any to be able to access private props. maybe we could consider making those public aswell, since we are not really using private methods. or change everything to be private methods ex: #example = () => void

The binding tests are poor.
There are multiple tests of this form

  it("Should set its own properties correctly", () => {

    interface Ninja { }
    const ninjaIdentifier = "Ninja";

    const binding = new Binding<Ninja>(ninjaIdentifier, BindingScopeEnum.Transient);
    
    const bindingInSyntax = new BindingInSyntax<Ninja>(binding);

    // cast to any to be able to access private props
    const _bindingInSyntax: any = bindingInSyntax;

    expect(_bindingInSyntax._binding.serviceIdentifier).eql(ninjaIdentifier);

  });

Why are we checking the serviceIdentifier ! Should be === on the binding.
Also for BindingWhenOnSyntax and BindingInWhenOnSyntax the _binding field is not used !
The test for BindingInSyntax is not required as we are testing that the scope gets changed !

binding_when_on_syntax.test.ts and binding_in_when_on_syntax.test.ts

Both of these just pass on, yet they do not test that they call with the correct parameter or return correctly !


Given that these types are never exposed there is no reason why we cannot make them public readonly

Also given that these are all exposed with interfaces is there any reason why BindingToSyntax isn't the only binding syntax class ?

@PodaruDragos
Copy link
Member

Also given that these are all exposed with interfaces is there any reason why BindingToSyntax isn't the only binding syntax class ?

I don't really understand what you are asking here.

I have one more thing I want to propose. What if we do this export type Newable<T> = new (...args: never) => T; this way we drop the any and it behaves exactly the same ( we still don't have any typesafety for the ...args ) and then where we need to or overlap with other ...args we just cast them from unknown to never. I think just toConstructor does that. What are your thoughts on this ?

Also do you think there is a way to properly cast target in injectable , decorate , _decorate just so it's not any anymore.

Also regarding @multipleMetadataDecorator

    @inject<Thing>("Thing")
    @inject("Thing") thing: Thing

Is this not more or less the same thing ?

@tonyhallett
Copy link
Contributor

tonyhallett commented Sep 3, 2021

Also given that these are all exposed with interfaces is there any reason why BindingToSyntax isn't the only binding syntax class ?

I don't really understand what you are asking here.

I am saying why have separate binding syntax classes. Why not put all functionality in a single class that inherits all interfaces - BindingToSyntax given that it is the entry. The return values are interfaces and ensure correct call order. The single class just returns itself for the next call.

Also regarding @multipleMetadataDecorator

    @inject<Thing>("Thing")
    @inject("Thing") thing: Thing

I assume that you mean replace injecting in setter with injecting the field.
I am injecting in a setter for a reason. So they are not the same thing at all.

export type Newable = new (...args: never) => T;

Why are you doing this ?
Have you tried it throughout the code ?

toConstructor should really be
toConstructor(constructor: T)
but we do toConstructor<T2>(constructor: Newable<T2>): so that it can be newed.

I think that we should do this

public toConstructor<T2>(constructor: interfaces.Newable<T2>)): interfaces.BindingWhenOnSyntax<T> {
    this._binding.type = BindingTypeEnum.Constructor;
    this._binding.implementationType = constructor as unknown as T;

Going to have to come back to you

Also do you think there is a way to properly cast target in injectable , decorate , _decorate just so it's not any anymore.

@PodaruDragos
Copy link
Member

I assume that you mean replace injecting in setter with injecting the field.
I am injecting in a setter for a reason. So they are not the same thing at all.

my apologies, didn't actually check the code ( I was curios just about the typings )

I am saying why have separate binding syntax classes. Why not put all functionality in a single class that inherits all interfaces - BindingToSyntax given that it is the entry. The return values are interfaces and ensure correct call order. The single class just returns itself for the next call.

That would be better in every way, yes.

Why are you doing this ?
Have you tried it throughout the code ?

Yes seems to work, will have to double check tough.

Going to have to come back to you

looking forward

remove more any's
remove casts to any
make metadata generic
@PodaruDragos
Copy link
Member

@tonyhallett I have pushed another commit ( I honestly don't know how to get rid of the remaining any's.
Do you have time to maybe look at that ?

I also resolved your feedback.
Let me know what you think.

@tonyhallett
Copy link
Contributor

@PodaruDragos

Going to be busy for a few days. Will have a look soon.

@jakehamtexas
Copy link
Contributor

jakehamtexas commented Oct 7, 2021

@PodaruDragos In case it adds any context, this looks to me like where the error in the test case may be originating from:
image

It looks like _createSubRequests is failing as expected given the nature of the test case, but that context.plan is undefined for some reason.

Looking at the body of _createSubRequests, it appears that what could be throwing is the invocation of _getActiveBindings.

image

I'm inferring this because we use context.addPlan after that invocation, which would prevent context.plan from being undefined in the parent scope. I'm a little in the weeds trying to understanding the _getActiveBindings method, so I'm not sure how much more investigation I can manage.

An interesting final piece of context, it seems about five months ago this change was made in the commit history which makes accessing context.plan.rootRequest more unsafe:

image

Here is the associated PR: #1132

I am willing to bet the original code was meant to cover up an intermittent regression in accessing this property, and it was deemed unnecessary in the new PR and was thus removed. Maybe it was not time to move it yet and the root problem is still unsolved, or has returned?

Here is a comment in the PR which discusses the change: https://github.com/inversify/InversifyJS/pull/1132/files#r623122372

cc: @tonyhallett

@tonyhallett
Copy link
Contributor

I will look to see if the removal of the code was a bad idea. It seems like it was.

@dcavanagh dcavanagh marked this pull request as ready for review October 7, 2021 23:32
@dcavanagh dcavanagh merged commit 772ea8e into master Oct 7, 2021
@dcavanagh dcavanagh deleted the update-typescript-compiler-options branch October 7, 2021 23:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants