Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Convert to TypeScript #356

Merged
merged 2 commits into from
Jun 28, 2018
Merged

Convert to TypeScript #356

merged 2 commits into from
Jun 28, 2018

Conversation

alexlafroscia
Copy link
Collaborator

@alexlafroscia alexlafroscia commented Jun 18, 2018

  • Re-writes the logic in TypeScript
  • Drops many of the JSDoc comments in favor of the explicit TypeScript typings

Closes #346

Todo

  • Fix service registry entry

@alexlafroscia
Copy link
Collaborator Author

It's TBD on whether this will need to be a breaking change or not. I'm converting the AjaxError classes over to actual classes, which may not work on all Ember versions.

Since that'll make maintenance easier, I think I'm OK with supporting Ember 2.4+ or something like that, if it means we can use some of the modern features in Ember. I don't really feel like active 1.13 maintenance is really necessary any more.

@alexlafroscia alexlafroscia force-pushed the typescript branch 4 times, most recently from 614e22a to 9268de7 Compare June 18, 2018 22:37
// DO NOT DELETE: this is how TypeScript knows how to look up your services.
declare module '@ember/service' {
interface Registry {
ajax: any;
Copy link
Collaborator Author

@alexlafroscia alexlafroscia Jun 18, 2018

Choose a reason for hiding this comment

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

I couldn't get this right, so I just set it to any for now.

If I export the service like this instead:

export default class AjaxService extends Service.extend(AjaxRequestMixin);

some of my tests started complaining that I wasn't using new with the class. I really need to fix this before merging, though, or most people that are looking up the service through an injection won't actually benefit from all the type definitions!

@@ -0,0 +1,12 @@
import url from 'url';

interface ModuleRegistry {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This bit was kind of weird and hard to figure out, but it allowed me to get around not having types for the FastBoot global yet.

@alexlafroscia
Copy link
Collaborator Author

alexlafroscia commented Jun 18, 2018

@Bouke @chriskrycho Would you guys look this over? I tried to add you as reviewers by GitHub won't let me ☹️

@alexlafroscia alexlafroscia changed the title [WIP]: Convert to TypeScript Convert to TypeScript Jun 18, 2018
@Bouke
Copy link

Bouke commented Jun 19, 2018

I've created a gist with my typings. They might not be fully covering and/or incorrect. I'm also quite new to TypeScript, so there might be better ways to do things.

*/
post(url, options) {
post(url: string, options?: AJAXOptions): AJAXPromise<Response> {
Copy link

Choose a reason for hiding this comment

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

See my typings where I have generic variants for all the verbs, so for example;

        post(url: string, options?: JQuery.AjaxSettings): RSVP.Promise<any>;
        post<T>(url: string, options?: JQuery.AjaxSettings): RSVP.Promise<T>;

This allows for clean code on the consumer's side, as the return type is already defined.

Copy link
Collaborator Author

@alexlafroscia alexlafroscia Jun 19, 2018

Choose a reason for hiding this comment

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

Makes sense to me, but could you give an example of what that would look like in use? I thought about going that direction with the type definitions, but decided against it because we actually have no way of knowing what the shape actually is.

My guess is that your proposition allows the user to say something like this:

interface User {
  name: string;
}

const user = await get<User>(this, 'ajax').get('/users/1');

and allow their application to know that user,name is a string, and give the right Intellisense?

My reservation here is that we have no way to know that user is actually matching the shape of the User interface; we could tell TypeScript that that's the case, but we have no way to verify it. I think it would actually be safer to keep the AJAXPromise<any> return type because it's closer to what we can actually guarantee is true about the system.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

On the other hand, we could take a "user at your own risk" attitude toward the generic type with something like this:

post<T = Response>(url: string, options?: whatever): AjaxPromise<T>

since that would basically tell people that, if left unspecified, the return value is going to resolve to any. However, if they want to tell the compiler what the type should be treated as, they can -- at their own risk, because they may actually be wrong and cause a runtime error that TypeScript can't help them with.

I think I like this idea best, since it is kind of the "best of both worlds" -- if a user wants to opt into this feature, they can, or else fall back to the original behavior I described, which is arguably safer but might be less helpful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Alright, that's what I did! Thanks for suggesting the generic.

I like the option of having it, if the user is confident in the structure of their JSON response and wants to get the richer experience, but by default it will be of type Response (which is an alias for any).

What's nice is that request and raw can both be parameterized by a type, even though raw actually has a return type of AjaxPromise<RawRequest<T>>. Adding in the generics was fun!

Copy link

@Bouke Bouke left a comment

Choose a reason for hiding this comment

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

Overall looks good to me 👍 , however I'm also just beginning to learn TypeScript. As commented elsewhere, adding generics for the verbs would allow the consumer to increase type safety in their code.

@alexlafroscia
Copy link
Collaborator Author

alexlafroscia commented Jun 19, 2018

cc: @Bouke

Thanks for adding your typings! As a fellow TypeScript newb, we can learn some stuff together here!

What do you mean, by trying to add a file? I'm not sure what you mean.

@Bouke
Copy link

Bouke commented Jun 19, 2018

What do you mean, by trying to add a file? I'm not sure what you mean.

Sorry, must've been the early hour -- I tried to reply to a different issue in a different repository.

@alexlafroscia
Copy link
Collaborator Author

No problem!

@alexlafroscia alexlafroscia merged commit f71854f into master Jun 28, 2018
@Turbo87 Turbo87 deleted the typescript branch March 3, 2019 11:45
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants