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

Fixed a type compatibility with Svelte's readables #3063

Merged
merged 1 commit into from
Feb 19, 2022
Merged

Conversation

Andarist
Copy link
Member

fixes #2533

@changeset-bot
Copy link

changeset-bot bot commented Feb 18, 2022

🦋 Changeset detected

Latest commit: c4ed71e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
xstate Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@@ -0,0 +1,12 @@
name: 'CI checks'
runs:
using: 'composite'
Copy link
Member Author

Choose a reason for hiding this comment

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

I had to add svelte-check to our CI jobs here and I've thought that it would be nice to experiment with those composite actions - we'll see how it goes, it's the first time when I've attempted to use this.

@ghost
Copy link

ghost commented Feb 18, 2022

CodeSee Review Map:

Review these changes using an interactive CodeSee Map

Review in an interactive map

View more CodeSee Maps

Legend

CodeSee Map Legend

@codesandbox-ci
Copy link

codesandbox-ci bot commented Feb 18, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit c4ed71e:

Sandbox Source
XState Example Template Configuration
XState React Template Configuration

@@ -15,9 +15,7 @@
"test": "jest",
"test:core": "npm test --prefix packages/core",
"dev": "node ./scripts/dev.js",
"ci": "npm run build && npm run test",
Copy link
Member Author

Choose a reason for hiding this comment

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

from what I can tell this wasn't actually used by anything

"changeset": "changeset",
"prerelease": "npm run build && npm run test",
Copy link
Member Author

Choose a reason for hiding this comment

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

"pre*" scripts dont work with all package managers, so I've decided to just move this directly to a github action

@@ -4,33 +4,6 @@ import { terser } from 'rollup-plugin-terser';
import rollupReplace from 'rollup-plugin-replace';
import fileSize from 'rollup-plugin-filesize';

const stripSymbolObservableMethodPlugin = ({ types: t }) => {
Copy link
Member Author

Choose a reason for hiding this comment

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

It's just no longer needed since I've figured out how to assign symbolObservable to a "variable" and maintain the Symbol.observable type at the same time

@@ -529,15 +529,18 @@ export function isObservable<T>(value: any): value is Subscribable<T> {
}
}

export const symbolObservable = (() =>
const symbolObservable = (() =>
Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, what happens in this file is weird and I don't have much on my defense... except... this TS playground

@@ -386,3 +387,23 @@ describe('Typestates', () => {
expect(failed).toEqual({ result: none, error: 'oops' });
});
});

describe('interpreter', () => {
it('should be convertable to Rx observable', () => {
Copy link
Member Author

Choose a reason for hiding this comment

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

an explicit test covering for changes from: https://github.com/statelyai/xstate/pull/2371/files

@@ -0,0 +1,19 @@
<script lang="ts">
// this file acts as a type test
import { createMachine, interpret } from 'xstate';
Copy link
Member Author

Choose a reason for hiding this comment

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

this is a new test for what is being fixed in this PR

Comment on lines +1609 to +1611
export interface InteropSubscribable<T> {
subscribe(observer: Observer<T>): Subscription;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

In a way, this breaks the previous contract exposed under Symbol.observable method. However, this is the only signature that is valid from Rx's PoV. The InteropObservable returns Subscribable<T>:
https://github.com/ReactiveX/rxjs/blob/67cb317a7a6b9fdbd3d2e8fdbc2ac9ac7e57179c/api_guard/dist/types/index.d.ts#L321-L323
and Subscribable is defined as follows:
https://github.com/ReactiveX/rxjs/blob/67cb317a7a6b9fdbd3d2e8fdbc2ac9ac7e57179c/api_guard/dist/types/index.d.ts#L690-L692

So, in fact, this interface only accepts observers - it doesn't accept separate listener functions for next, error and complete.

By implementing this change and using this as an explicit return type of the Symol.observable method on the Interpreter class we ensure that it's compatible with the Rx's signature for this:

public [symbolObservableRef.symbol](): InteropSubscribable<
State<TContext, TEvent, TStateSchema, TTypestate, TResolvedTypesMeta>
> {
return this;
}

Thanks to that we can revert the reordering of the subscribe's overloads from this PR and fix the issue with Svelte's readables. This is because both libraries are using conditional types to match the input argument and to "extract" the emitted type and conditional types are only seeing the last overload.

So, in a sense, this is a hack and might break any minute... cause the whole thing is fitting both libraries thanks to the alignment of the stars and not because this is built on super solid principles. We trick Rx by only exposing a single overload with the observer as the parameter for its conditional type from the Symbol.observable method and we trick Svelte by reordering overloads so it only sees the one with callbacks parameters.

Comment on lines +1213 to +1214
const observer = toObserver(next);
listeners.add(observer.next);
Copy link
Member Author

Choose a reason for hiding this comment

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

this is a fix from the perspective of the Symbol.observable - since that method is accepting observers we convert the received callback (or observer) to an observer

@Andarist Andarist force-pushed the andarist/fix-2533 branch 3 times, most recently from b8b4a79 to f5485bd Compare February 18, 2022 19:30
@Andarist
Copy link
Member Author

CI is expected to fail right now. It rightfully reports errors in some svelte files related to state.matches typings - this is a new error from CI's perspective because we actually type-check those svelte files now. The error was there all along, it just slipped through the cracks because CI was not verifying those files.

I'll look into fixing this problem and I think it's OK to wait with this PR a little bit before I do so.

@Andarist
Copy link
Member Author

The CI should get unblocked in a sec since I've landed #3065

@Andarist Andarist marked this pull request as ready for review February 19, 2022 09:52
@Andarist Andarist merged commit c826559 into main Feb 19, 2022
@Andarist Andarist deleted the andarist/fix-2533 branch February 19, 2022 13:57
@github-actions github-actions bot mentioned this pull request Feb 19, 2022
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.

Version 4.23.0 breaks typing of "$" prefixed service inside svelte component
2 participants