-
Notifications
You must be signed in to change notification settings - Fork 26.2k
Use typed get method in TestBed class #26491
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
Comments
did u added the above service in providers |
A PR would be great! |
@mhegazy I'll try to get into it. No promises. |
@michaeljota hiya, I was facing this same issue today and found your report, are you working on a PR? otherwise I'm thinking I can try to send one, just didn't want to step over |
Hi @Goodwine. I haven't get a chance to look at this. You can give it a look if you want. Thanks! |
My proposal is to use these types - get<T>(token: InjectionToken<T>): T;
get<T>(token: Type<T>): T;
get(token: T): unknown;
get<T1, T2>(token: InjectionToken<T1>, notFoundValue: T2): T1|T2;
get<T1, T2>(token: Type<T1>, notFoundValue: T2): T1|T2;
get<T2>(token: T, notFoundValue: T2): unknown; The reason for using There is one problem with this approach though. What if the user wants to use the abstract class interface? Or what if the user knows the real value? Unfortunately this is kinda annoying to do in TS because if we have an abstract class Perhaps the return value should be // bad?
const foo = TestBed.get(Foo); // returns "never"
// good?
const foo = TestBed.get(Foo as Type<Foo>) // returns type Foo Problem is that this could be anything and the user could cast to whatever they want, so maybe returning |
I would consider an approach that reduce type casting, as I think is just about that. |
@Goodwine What do you think about something like this: get<T>(token: T | InjectionToken<T>, notFoundValue?: T): T extends new (...args: any[]) => any ? InstanceType<T> : T; I think this would reduce type casting. I'm want to be sure that I understand the usage of |
I was pretty sure there was a way to get One thing I'm still not sure what to do about. get<T1, T2>(token: T1, notFoundValue: T2): T1|T2; Should this be |
Strictly speaking, In any case, I don't think there is an advantage using About the usage of an abstract class as a token, not even with
Maybe return |
I can apparently use type AbstractType<T> = T extends { prototype: infer T } ? T : never; Resulting in: get<T>(token: InjectionToken<T>): T;
get<T>(token: T): T extends Type<unknown> ? InstanceType<T> : AbstractType<T>;
get<T1, T2>(token: InjectionToken<T1>, notFoundValue: T2): T1 | T2;
get<T1, T2>(token: T1, notFoundValue: T2): T1 extends Type<unknown> ? InstanceType<T1>|T2 : AbstractType<T1>|T2; I really disagree with using |
I don't is necessary that many overloads. And I'm not sure about AbstractType. Check this:
|
The reason it's not working in your example is because your I'm thinking that it's possible to have: get(x: T): T extends InjectionToken<any> ? T : T extends Type<any> ? T : AbstractType<T>; But I feel like it's too annoying to read and reason about. Regarding why having overload for whether the second argument is present, because I'm using get(x: T, y?: T2): (T extends InjectionToken<any> ? T : T extends Type<any> ? T : AbstractType<T>)|(T2 extends undefined ? never : T2); But I have the same concern of this being too hard to read. |
(reason for using |
If you don't supply an additional argument, it would return What Angular does underneath shouldn't be a concern, but instead it should be to express better the intention of the function. However, I don't know if there is value in returning BTW: In deed, I test with |
@Goodwine I still not sure about If you want to get something, say |
So the reason I chose to use 2 types is because you may want to do I can't think of other reason and to be honest I've never seen any other uses except for within Angular's code base, but that's not to say they are implementation details, as far as I'm aware this is all part of the public API. There are also "options" that can be passed to get() as a second argument, they are Otherwise I agree with you, I'd much rather have only 1 type in there. But to be fair, if you add something on the second parameter that has a different shape, the type would protect you now, and if you add a mock/spy, and now that I think even more about it, I wonder why do we even have that option for TestBed given that in a test you probably shouldn't be using the second parameter. Hm... |
Why would you want to get null if not found? I'm trying to understand that scenario. |
That's just to support the existing use of To be honest I'd like to get rid of the second param for |
Talking with the angular team (I'm not part of the angular team), I'll actually send PRs in the following order:
|
This new interface will match classes whether they are abstract or concrete. Casting as `AbstractType<MyConcrete>` will return a type that isn't newable. This type will be used to match abstract classes in the `get()` functions of `Injector` and `TestBed`. Type isn't used yet so this isn't a breaking change. Issue #26491 PR Close #29295
Adds an overload to TestBed.get making parameters strongly typed and deprecated previous signature that accepted types `any`. The function still returns `any` to prevent build breakages, but eventually stronger type checks will be added so a future Angular version will break builds due to additional type checks. See previous breaking change - #13785 Issue #26491 PR Close #29290
This new interface will match classes whether they are abstract or concrete. Casting as `AbstractType<MyConcrete>` will return a type that isn't newable. This type will be used to match abstract classes in the `get()` functions of `Injector` and `TestBed`. Type isn't used yet so this isn't a breaking change. Issue angular#26491 PR Close angular#29295
Adds an overload to TestBed.get making parameters strongly typed and deprecated previous signature that accepted types `any`. The function still returns `any` to prevent build breakages, but eventually stronger type checks will be added so a future Angular version will break builds due to additional type checks. See previous breaking change - angular#13785 Issue angular#26491 PR Close angular#29290
This new interface will match classes whether they are abstract or concrete. Casting as `AbstractType<MyConcrete>` will return a type that isn't newable. This type will be used to match abstract classes in the `get()` functions of `Injector` and `TestBed`. Type isn't used yet so this isn't a breaking change. Issue angular#26491 PR Close angular#29295
Adds an overload to TestBed.get making parameters strongly typed and deprecated previous signature that accepted types `any`. The function still returns `any` to prevent build breakages, but eventually stronger type checks will be added so a future Angular version will break builds due to additional type checks. See previous breaking change - angular#13785 Issue angular#26491 PR Close angular#29290
Per discussion with @vikerman, the Angular team can't accept such a breaking change at this point, so the approach we'll now take is to create a new method |
TestBed.get is not type safe, fixing it would be a massive breaking change. The Angular team has proposed replacing it with TestBed.inject and deprecate TestBed.get. Deprecation from TestBed.get will come as a separate commit. Issue #26491 Fixes #29905 BREAKING CHANGE: Injector.get now accepts abstract classes to return type-safe values. Previous implementation returned `any` through the deprecated implementation. PR Close #32200
…32200) TestBed.get is not type safe, fixing it would be a massive breaking change. The Angular team has proposed replacing it with TestBed.inject and deprecate TestBed.get. Deprecation from TestBed.get will come as a separate commit. Issue angular#26491 Fixes angular#29905 BREAKING CHANGE: Injector.get now accepts abstract classes to return type-safe values. Previous implementation returned `any` through the deprecated implementation. PR Close angular#32200
…32200) TestBed.get is not type safe, fixing it would be a massive breaking change. The Angular team has proposed replacing it with TestBed.inject and deprecate TestBed.get. Deprecation from TestBed.get will come as a separate commit. Issue angular#26491 Fixes angular#29905 BREAKING CHANGE: Injector.get now accepts abstract classes to return type-safe values. Previous implementation returned `any` through the deprecated implementation. PR Close angular#32200
From 9.0.0 use TestBed.inject See angular#32200 Fixes angular#26491 PR Close angular#32406
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
I'm submitting a...
Current behavior
The
get
static method ofTestBed
class does not return a typed object.Expected behavior
The
get
static method should return a typed object.Minimal reproduction of the problem with instructions
Look examples.
What is the motivation / use case for changing the behavior?
This would improve type safety.
Environment
Others:
A possible implementation using new helper types from TypeScript would be:
I'm not sure if the
notFoundValue
should be a constructor or an instance, so I typed it as both, but fell free to update it as is actually needed. I tested that signature and it actually returns a typed object as wanted.The text was updated successfully, but these errors were encountered: