Skip to content

TypeScript performance #1406

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

Closed
1 of 2 tasks
RWOverdijk opened this issue Oct 25, 2019 · 14 comments
Closed
1 of 2 tasks

TypeScript performance #1406

RWOverdijk opened this issue Oct 25, 2019 · 14 comments

Comments

@RWOverdijk
Copy link

Question

  • I've checked documentation and searched for existing issues
  • I tried the spectrum channel

I have no idea where or why exactly but sometimes my IDE (webstorm) goes insane, running 100% on all my cores in some odd cases.

I've found that if I do not specifically state the source of a store for example, this happens. One such example is:

export class SpaceScreen extends Component<SpaceProps, SpaceState> {
  get venueStore() {
    return this.props.rootStore.venueStore as Instance<typeof VenueStore>;
  }
}

If I don't add the as Instance<typeof VenueStore> webstorm tries to destroy my macbook.

Another issue I've found is using getParent (rootStore) never allows me to type properly, saying:

... implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer

if I try:

const rootStore = (getParent(self) as Instance<typeof RootStore>);

Maybe this is something that's known, but it's pretty hard to figure out why these things happen.

PS: Are there plans to give typescript more love with MST? Or doesn't it need any and is my thought on that wrong?

@Bnaya
Copy link
Member

Bnaya commented Oct 25, 2019

it happens to me in vs code as well.
it's due to the inference complexity.

Take a look on:
microsoft/TypeScript#25023 (comment)
in the linked comment there's my "workaround"

@RWOverdijk
Copy link
Author

RWOverdijk commented Oct 26, 2019

I'll give that a go. But it doesn't fix the:

implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer

Do you have any tricks for that as well? (besides typing rootstore as any explicitly).

Also: is it an idea to think about an overhaul? Maybe something like classy-mst but with decorators for example? I love the way MST is supposed to work, but truth is that it can be a headache with typescript (especially for example when there's a TS error where the message is the size of a mountain). I'd love to work on that as well.

@Bnaya
Copy link
Member

Bnaya commented Oct 27, 2019

Take a look at:
https://codesandbox.io/s/mst-issue-1406-olsn3

@RWOverdijk
Copy link
Author

@Bnaya I meant this: https://codesandbox.io/s/brave-lederberg-1dqpo?fontsize=14

Look in TestStore.ts.

image

@terrysahaidak
Copy link

terrysahaidak commented Oct 28, 2019

@RWOverdijk did you try to use generic param with getParent?

@kenaku
Copy link

kenaku commented Oct 28, 2019

implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer

This happens when you use getRoot() or getParent() in views/actions.
But you have to make it in ALL of your views/actions across your store to fix issue.
You have to explicitly set return values of that views/actions (including flow actions)
Also, when we refactored whole store like this, CPU usage by Typescript dropped significantly.

Example:

    get store(): IStore {
      return getRoot(self)
    },
    get language(): string {
      return this.store.language
    },


@RWOverdijk
Copy link
Author

@kenaku I don't understand what you're saying. Having a getter (assuming you mean a view?) like this won't work if I use "this" and the context isn't the same (which happens frequently).

Also not sure what "IStore" is.

In any case I tried it and it doesn't solve the issue (you can solving try it here: https://codesandbox.io/s/brave-lederberg-1dqpo?fontsize=14 and see what I mean).

@RWOverdijk
Copy link
Author

@terrysahaidak It's RWOverdijk 😄 And it doesn't make a difference. I tried getParentOfType, I tried getParent with generic typeof RootStore and I tried generic Instance<typeof RootStore>. All of which yield the same result. Also reproducable in the codesandbox link.

@mweststrate
Copy link
Member

mweststrate commented Oct 28, 2019

The error you get is correct, as TypeScript doesn't support recursive types at the moment (3.7 might change that!). Since the type of your store depends on the output on the signature of that view, which, to determine it's result type, needs to know the type of.... you see the circle quickly.

However, since interfaces can be recursive, you can fix this by using the trick explained in the docs: Make sure you introduce the type export interface I{MODEL} extends Instance<typeof {MODEL}> {} for every model type you create.

After that, you can use that interface wherever needed to 'break' the cycle in the types. Without loosing strong typing.

I applied the change here: https://codesandbox.io/s/serene-fog-oryt3. Note that calling .test is now strongly typed again. With this trick and sprinkling these interface any cycles can be fixed afaik. it might not always be immediately clear where you need it, but if you strongly type all action / view returns, it gets you quite far. (And I think that this a really good practice anyway).

It is a bit cumbersome, but usually straightforward mechanism. So I guess we have to live with it until TS supports recursive types 😅

An added benefit is that it makes TS a lot faster as well.

@terrysahaidak
Copy link

terrysahaidak commented Oct 28, 2019

Sorry, @RWOverdijk, I've been typing from my phone without autocomplete :(

@mweststrate any link where I can read about that TS update? Don't remember anything related to cyclic types.

@RWOverdijk
Copy link
Author

RWOverdijk commented Oct 28, 2019

@mweststrate Well well well... Look at that. I see it requires a two-step approach of having rootStore first and then getting a nested store from that. I suppose I can live with that.

Isn't this whole "ISomeInterface" thing against the best practises/style guide? https://basarat.gitbooks.io/typescript/content/docs/styleguide/styleguide.html#interface

I don't know how much of an authority that doc is. I just remember a c# person saying they regret that convention and thought it would only make sense to then not apply it to TS.

Also, now that I have your attention... Are there plans to do a rewrite/happier implementation written using typescript? I have some ideas on how I'd like that to work and was thinking of folding my own solution. You're working on immer (which btw does make me wonder, is that because you no longer like mst? Or because you have bigger plans? Or do you consider them unrelated?)) and I don't want to put in effort somewhere if you end up working on exactly what I'm looking to build.

I know, this issue is not an AMA but you know. At least I tried 😄

@mweststrate
Copy link
Member

mweststrate commented Oct 28, 2019 via email

@RWOverdijk
Copy link
Author

@mweststrate Nice, thanks for sharing that. I'll take a look.

I'll name my interfaces something other than II118nStore for now 😄 Maybe just a clear name like I18nStoreInstance and I18nStoreSnapshotIn. A bit long but clear.

Thanks again, everything works now :)

@lock
Copy link

lock bot commented Jan 14, 2020

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs or questions.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants