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

Add Span.toObject function, replacing Span.toJSON #592

Merged
merged 1 commit into from
Feb 3, 2022

Conversation

tombruijn
Copy link
Member

The Span.toJSON function required us to always parse it manually. Why
not do that in the function itself? That's what Span.toObject does.
Other name suggestions are welcome!

This way we don't cheat in tests and try and match on the JSON string
with toMatch(/substring/). Now we need to specify which attribute
value we want to match.

All fields of the SpanData object are optional because if no span data
is returned by the extension, all fields are empty.

Based on #591

The `Span.toJSON` function required us to always parse it manually. Why
not do that in the function itself? That's what `Span.toObject` does.
Other name suggestions are welcome!

This way we don't cheat in tests and try and match on the JSON string
with `toMatch(/substring/)`. Now we need to specify which attribute
value we want to match.

All fields of the SpanData object are optional because if no span data
is returned by the extension, all fields are empty.
Copy link
Contributor

@unflxw unflxw left a comment

Choose a reason for hiding this comment

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

This way we don't cheat in tests and try and match on the JSON string
with toMatch(/substring/). Now we need to specify which attribute
value we want to match.

👍💯

* The internal data structure of a `Span` inside the AppSignal Extension.
*/
export type SpanData = {
closed?: boolean
Copy link
Contributor

@unflxw unflxw Feb 3, 2022

Choose a reason for hiding this comment

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

The closed attribute should not be optional, I think, as it's present even when the span has been garbage-collected (or at least that's what toObject says)

Side note: one could also do something like

type SpanData = ClosedSpanData | OpenSpanData
type ClosedSpanData = { closed: false }
type OpenSpanData = {
  closed: true,
  name: string,
  ...
}

This way, once the tests check that closed != false (for example, by throwing an error if it's closed) then the compiler will infer it's an OpenSpanData from that point onwards, and the other attributes can be accessed without the .! syntax.

I've been playing with this idea in the TypeScript playground for a bit. None of this is necessary, I just think discriminated unions are neat.

Copy link
Member Author

Choose a reason for hiding this comment

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

The closed attribute should not be optional, I think, as it's present even when the span has been garbage-collected (or at least that's what toObject says)

It's not set if no data is returned from the extension at all. Would fit that into the union?

Copy link
Contributor

@unflxw unflxw Feb 3, 2022

Choose a reason for hiding this comment

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

Huh, adding the empty object as an option makes this surprisingly tricky. I've tried fitting it into the union in several ways, by adding an additional EmptyThing = {}, or by making the closed property optional in the ClosedThing object, or some mix of the two. Thing is, it seems like if it's optional, it can't be a discriminant the compiler will still consider it possible, even if you check for undefined. And if there's an EmptyThing declaration in the union, then you can't easily check for the property -- it's a type error to try to access a property that doesn't exist in the object.

The only way I've been able to make it work in a way that is type-sound is using this magically typed version of Object.hasOwnProperty that I found on the internet. It's a bit ugly, as you have to re-implement hasOwnProperty just to make the compiler happy. Here's a playground showcasing it.

That said, you can use type guards, like isOpen in these examples, to define your own rules for what makes one type a different type. This is simpler and also works.

Copy link
Member Author

Choose a reason for hiding this comment

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

Wow cool! But that seems like a lot for something we only use in the test suite, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah yes, definitely! 😅 Sorry, got carried away. Type systems are fun, in their own way. Disregard the above.

@tombruijn tombruijn merged commit 32d8054 into test-span-type Feb 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants