-
Notifications
You must be signed in to change notification settings - Fork 18
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
Copy flow files so that the module returns typed values #51
Conversation
Thanks for putting this together, it's good to see how this approach looks in practice. It's very surprising to me that the Flow compiler doesn't have any option to generate public types for each module it encounters. In TypeScript, One issue with the Thinking out loud: how do other major production projects generate typings for their compiled code using Flow? This seems like an incredibly important feature for Flow to omit. Imagine a massive project with hundreds of files that will ultimately be distributed via NPM; are the two options really to copy entire source trees or to hand-roll types? |
We might take a look at how React does it, as they're probably the biggest project that does Flow typing. Although since they're Facebook, too, they might even have |
What about using Babel to convert type annotations to comments? This may be a happy medium: we only ship built code, but the built code contains commented-out type annotations that are still picked up by Flow. I'd personally be OK with uglier (and larger) compiled code if it included type annotations, especially since the type comments could be stripped out in downstream projects as long as the projects are built (regardless of whether they use Flow.) |
I'm game, didn't even know that babel plugin existed. Looks like react types are indeed built directly into flow. |
So I gave First thing I noticed - the compiled files still don't have a Secondly, it seems like flow comments either don't work with all flow code, or either the plugin itself doesn't cover all of flow's language feature. After compiling
The |
Not sure I see the need to move away from index.js.flow Could we add a libdef to it and make sure it gets bundled in the package? Most and Ava do something similar: |
@amccloud 100% down to try the libdef approach. One thing I want to point out, though, is that neither of those projects use flow internally. They're just providing a libdef. The copy source method is useful when you use flow internally and want other people to be able to use your types, basically without you having to exert any extra effort, since your exported API is already typed. |
I'd like to make one last argument in favor of this PR &
|
@rickharris seems worth it if you get a libdef for free! Can we ever opt-out of publishing a type or is any type we export internally also a public type because it will be copied? |
That's a good question. We could control what gets exported from the index. So say that we have It might also be possible to only copy |
8ec4257
to
8c260c1
Compare
@amccloud do you have thoughts on the issue I described in the main PR description?
|
@rickharris that was sorta intentional because depending on the transport the endpoint may not be available. We could make AbstractCLI implement everything but stub/throw if something not supported by cli is called? |
🤔 seems less than ideal for the default AUTO case which will have everything. Assuming that |
Had a convo with @amccloud and there's still a lot to figure out about our exported types for this package, but in the meantime we might as well merge this so we have types for the existing code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally, it works. Seems like a reasonable solution
✅ from me
package.json
Outdated
@@ -12,7 +12,7 @@ | |||
}, | |||
"scripts": { | |||
"prepublish": "yarn run build", | |||
"build": "babel ./src -d ./lib", | |||
"build": "babel ./src -d ./lib && flow-copy-source src lib", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice to switch the order of these so the babel options like --watch
can still be used with build
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also nit: ./src ./lib to match all the other relative paths
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. We'd probably want a kind of watch
command to do both of these things, wouldn't we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea something like that or like start
for development
info: ( | ||
userDescriptor: UserDescriptor | ||
) => Promise<User> | ||
info: (userDescriptor: UserDescriptor) => Promise<User> | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we export some/all of these types in index.js
so that we can have access to Abstract.ShareDescriptor
or Abstract.types.ShareDescriptor
in application code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works nicely and feels like a good immediate solution.
@amccloud we could export whatever types we need, sure, but I'm not 100% convinced by that example. I'd rather see that component define it's own requirements and hide its internal usage of abstract-sdk. For instance, if it ever needed another ID passed to it that wasn't part of |
@rickharris descriptors are public API https://sdk.goabstract.com/docs/abstract-api/#descriptors Individual properties like Edit: You could still depend on individual properties if you need to because their type is just a string |
@amccloud I'm confused about what points you're making here. Descriptors are still just objects of string ids, like you said in your edit, right? |
@rickharris descriptors are now valid dependencies too, so components should prefer to depend on descriptors if they can: type Props = {
params: Abstract.LayerDescriptor,
layer: Abstract.Layer // would be nice too
}; |
@@ -55,7 +55,7 @@ export type PageDescriptor = {| | |||
|
|||
export type LayerDescriptor = {| | |||
...ObjectDescriptor, | |||
sha: $PropertyType<ObjectDescriptor, "sha"> | "latest", | |||
sha: $PropertyType<ObjectDescriptor, "sha">, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rickharris I really think we should export all of the types that are documented and intended to be public API. It would be the types in the right sidebar here https://sdk.goabstract.com/docs/abstract-api/ and the subtypes we document like This PR could benefit from the types https://github.com/goabstract/ui/pull/202 and it was the intention all along with |
I agree with @amccloud. From a high level, consumers of a typed API should be able to use the same interfaces that make up that public API. |
We've had a bit of conversation about how we should enable external flow type checking when using this module, and although we're not in agreement quite yet, I am opening this PR for discussion of its merits and because it unblocks me in trying to incorporate this module into our projects.
The problem
By using
index.js.flow
as we would normally use atypes.js
file for all of our types, we end up exporting our types, but they're not actually used when we import non-types. For instance, if you importAbstract
isany
.The possible solution in this PR
Move the current
index.js.flow
totypes.js
and useflow-copy-source
to copy uncompiled source code tolib
, suffixed with.flow
. This way, when you import fromabstract-sdk
, the actual code comes from.js
files, but flow knows to look in their corresponding.js.flow
files for typings. This is a really simple way to tell flow the types of the things that come from your module.Now we have type checking and even completions working
Tracking some issues using the module with flow enabled
AbstractInterface
fromAbstract.Client
, you can't actually call something likeclient.projects.list
, becauseprojects
is a maybe onAbstractInterface
.