-
Notifications
You must be signed in to change notification settings - Fork 714
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
prepare typescript 4.5 #1407
prepare typescript 4.5 #1407
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1407 +/- ##
==========================================
- Coverage 99.85% 99.55% -0.30%
==========================================
Files 53 53
Lines 1367 1363 -4
Branches 192 196 +4
==========================================
- Hits 1365 1357 -8
- Partials 2 6 +4
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @PodaruDragos for your beautiful work in this PR 🙏
I have a few things that I would like to see changes about, and I am happy to discuss them more:
- Please reconsider the usage of
never
when defining a function type of unknown arity. (this tends to introduce complications with using the type and interacting with other types that depend on...unknown[]
). - Please reconsider making a member
public
without addressing the underlying code smell (please see my comment for a writeup about this).
src/utils/exceptions.ts
Outdated
|
||
export function isStackOverflowExeption(error: Error) { | ||
export function isStackOverflowExeption(error: unknown | Error): error is RangeError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since unknown
is a top type, unknown | Error
is the equivalent of simply unknown
to the compiler.
Lovely to see the usage of the is RangeError
type predicate though 👍
export function isStackOverflowExeption(error: unknown | Error): error is RangeError { | |
export function isStackOverflowExeption(error: unknown): error is RangeError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have noticed this situation of using SomeType | unknown
at least one other time, and I will try to find it, but I know I may miss it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would Error | unknown
work better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, unfortunately it is the same no matter the order @dcavanagh
Any type union with unknown
will simply be unknown
without any of the other union members
src/syntax/binding_to_syntax.ts
Outdated
@@ -6,7 +6,7 @@ import { BindingWhenOnSyntax } from "./binding_when_on_syntax"; | |||
|
|||
class BindingToSyntax<T> implements interfaces.BindingToSyntax<T> { | |||
|
|||
private _binding: interfaces.Binding<T>; | |||
public _binding: interfaces.Binding<T>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this, I think we should keep this member private
and use the same tricks that are in use elsewhere to make it accessible with an as unknown as { _binding: interfaces.Binding<T> }
, but only for now :). Please see my following comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this is uncovering a smell.
I have noticed in the past that this member is private
, but a type assertion is used in order to allow it to be accessed from a public location. This is a pattern that can be observed with other members, not just this one (for instance, _bindingDictionary
).
A few places I have noticed this are among test files:
test/container/container.test.ts
test/syntax/binding_when_on_syntax.test.ts
Another place is in src/planning/planner.ts
.
The reality of this smell is that there is a need for two forms of the containing types (in this case, I am referring to BindingToSyntax
since this is where we have concentrated this specific example):
- A presentational version which maintains a correct API for the consumers of the package, and does not expose unnecessary members like
_binding
. - An internal version which allows a more exposed API for the purposes of testing and proper layer integration with
planner
and friends.
I think that a good way of accomplishing this which resolves the smell is to rename the class with a _
prefix, as in BindingToSyntax => _BindingToSyntax
, etc. This means that the current definition of this class will become the internal form of the class. Then, any members which are meant to be public may be accomplished in the following manner:
// Please ignore the lack of generic type vars, etc.,
// as this is only meant to be an example
class BindingToSyntax {
constructor(
private _internal = new _BindingToSyntax(...args)
) {}
get somePublicMemberFromOriginalImplementation() {
return this._internal.somePublicMemberFromOriginalImplementation;
}
}
etc.
Finally, with a presentational/internal pattern like this, we are free to fix the original problem for those classes which have the behavior of needing a private member exposed for testing, or for use in planner
or similar. We can simply make the members that needed this special access despite being private
members into public
ones instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you agree @PodaruDragos then I will spin the above comment off as an issue for us to work on at some time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
totally agree with this. Do you also agree that we should just move everything to actual #private
fields since you know they are really private
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is worth taking a look at cleaning this up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PodaruDragos I think we should definitely do #private
type of vars in the future, for now let's not increase the scope of this PR
let serviceIdentifier = serviceIdentifiers[index]; | ||
const injectIdentifier = (metadata.inject || metadata.multiInject); | ||
serviceIdentifier = (injectIdentifier) ? (injectIdentifier) : serviceIdentifier; | ||
const injectIdentifier = metadata.inject || metadata.multiInject; | ||
serviceIdentifier = (injectIdentifier ? injectIdentifier : serviceIdentifier) as interfaces.ServiceIdentifier<unknown> | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it was just simple type annotations being added here, but since injectIdentifier
isn't used outside of the assignment on line 80, it would be great if someday we could rewrite this in the following manner:
let serviceIdentifier = metadata.inject ?? metadata.multiInject ?? serviceIdentifiers[index];
Ideally this would avoid needing an explicit cast to interfaces.ServiceIdentifier<unknown> | undefined
, since (I hope) we have strictNullChecks
enabled.
This would be better enabled by making the return type of formatTargetMetadata
use interfaces.ServiceIdentifier<unknown>
for the inject
and multiInject
properties.
src/interfaces/interfaces.ts
Outdated
@@ -90,7 +92,7 @@ namespace interfaces { | |||
factory: FactoryTypeFunction | null | |||
}; | |||
|
|||
export type Provider<T> = (...args: any[]) => (((...args: any[]) => Promise<T>) | Promise<T>); | |||
export type Provider<T> = (...args: never[]) => (((...args: never[]) => Promise<T>) | Promise<T>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would highly recommend leaving this type as any
. never
is not really a good candidate for this use case.
In my mind, any
is acceptable for defining function args with unknown arity.
@@ -40,6 +40,8 @@ namespace interfaces { | |||
|
|||
export type Newable<T> = new (...args: never[]) => T; | |||
|
|||
export type Instance<T> = T & Record<string, () => void>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting choice here. I think there may be a better name for this type as it relates to the context it is used in.
- I like the idea of encapsulating this type with
type
keyword. - Calling it
Instance
feels a little undercooked since the right hand side of the assignment does not really imply to me that this type is exlusivelyInstance
-like. Does it seem possible that we could infer a better name from its usage? - Should we consider whether this should be exported publicly from the package? We tend to put all interfaces in this module, which makes them available to consumers of the package, but thinking of proper encapsulation, does a consumer of the package care about this type? Is there a better/closer place to put?
I'm personally ready to challenge the assumption that using interfaces.ts
for all interfaces and types is the correct pattern, but it's certainly not in scope for this one issue :) Maybe we should keep it here for now and thinking about breaking apart interfaces
in a future breaking changes release?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jakehamtexas I agree about the interfaces. interfaces.ts should really only export the interfaces we want to see in the public api.
@@ -1,7 +1,5 @@ | |||
const BindingCount = { | |||
export const BindingCount = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this a lot better. Maybe in the future this is better as an enum
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the work. Looking good and generating some discussion!
@@ -91,4 +91,4 @@ jobs: | |||
uses: codecov/codecov-action@f32b3a3741e1053eb607407145bc9619351dc93b # renovate: tag=v2 | |||
with: | |||
directory: coverage/ | |||
fail_ci_if_error: true | |||
fail_ci_if_error: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing new line
}; | ||
|
||
export { BindingCount }; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing new line
@@ -1,48 +1,9 @@ | |||
{ | |||
"name": "inversify", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we need this reorganized.
@@ -40,6 +40,8 @@ namespace interfaces { | |||
|
|||
export type Newable<T> = new (...args: never[]) => T; | |||
|
|||
export type Instance<T> = T & Record<string, () => void>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jakehamtexas I agree about the interfaces. interfaces.ts should really only export the interfaces we want to see in the public api.
src/syntax/binding_to_syntax.ts
Outdated
@@ -6,7 +6,7 @@ import { BindingWhenOnSyntax } from "./binding_when_on_syntax"; | |||
|
|||
class BindingToSyntax<T> implements interfaces.BindingToSyntax<T> { | |||
|
|||
private _binding: interfaces.Binding<T>; | |||
public _binding: interfaces.Binding<T>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is worth taking a look at cleaning this up
@@ -40,7 +40,7 @@ describe("Context", () => { | |||
const plan = new Plan(context, ninjaRequest); | |||
context.addPlan(plan); | |||
|
|||
expect(context.plan.rootRequest.serviceIdentifier).eql("Ninja"); | |||
expect(context.plan.rootRequest.serviceIdentifier).eql('Ninja'); | |||
}); | |||
|
|||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing new line
it('should thrown an exception non factory binding.type', () => { | ||
const binding = new Binding('', 'Singleton'); | ||
binding.type = 'Instance'; | ||
expect(() => getFactoryDetails(binding)).to.throw('Unexpected factory type Instance'); | ||
}); | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing new line
const id1 = id(); | ||
expect(id1).to.be.a("number"); | ||
expect(id1).to.be.a('number'); | ||
}); | ||
|
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing newline
|
||
const symbolWithoutDescription = Symbol(); | ||
expect(getSymbolDescription(symbolWithoutDescription)).to.equal(""); | ||
expect(getSymbolDescription(symbolWithoutDescription)).to.equal(''); | ||
}); | ||
|
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing new line
@@ -20,7 +20,10 @@ | |||
"max-file-line-count": false, | |||
"max-line-length": [ | |||
true, | |||
140 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would rather have the imports have line breaks after 3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps better under a different scope? (See previous formatting comment)
fadfa2b
to
6cc2d05
Compare
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6) --- updated-dependencies: - dependency-name: minimist dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Podaru Dragos <[email protected]>
6cc2d05
to
fb2a91e
Compare
Prepare for TS 4.5