zumra-mobile / docs/howto/libdefs.md
Libdefs
Zumra Mobile Apps for Android & iOS
Libdefs
Libdefs, or "library definitions", are files we use to annotate third-party code, when that code isn't well-typed. You can read more about Flow libdefs here.
Sometimes, installing a Flow libdef is as simple as, for an NPM
package named "foo", flow-typed install foo. This depends on
flow-typed being aware of a libdef for foo. FlowTyped maintains a
repository that people contribute libdefs to, and flow-typed install
checks that repository.
Sometimes, a published libdef doesn't exist, and in that case, more work is involved. This doc is meant to be updated with anecdotes or general workflow patterns in the effort to get our third-party dependencies well-typed.
remotedev-serialize
Some assembly was required for a libdef for remotedev-serialize, but
it was important to get one working 1. Here's a summary of what that
was like.
-
Check to see if someone has already submitted a libdef to FlowTyped, with
flow-typed install remotedev-serialize. They haven't; we get the output, '!! No flow@v0.92.0-compatible libdefs found in flow-typed for the explicitly requested libdefs. !! Consider usingflow-typed create-stub remotedev-serializeto generate an empty libdef that you can fill in.'. -
As that output suggests, run
flow-typed create-stub remotedev-serialize. This creates
flow-typed/npm/remotedev-serialize_vx.x.x.jsand fills it with a template based on the directory structure innode_modules/remotedev-serialize. Move this toflow-typed/remotedev-serialize_vx.x.x.js(nonpm) because we want to maintain it locally; we don't want local adjustments we make to get clobbered by an eventual libdef in the FlowTyped repo. Delete the metadata lines at the top; they work as a tag on libdef contents that come from the FlowTyped repo, which this one doesn't 2. -
Here, we could enter everything in manually, but it turns out that DefinitelyTyped has a TypeScript libdef for
remotedev-serialize3, which we can use as a starting point. So, copy that into a temporary local text file as, e.g., libdef.d.ts. -
Flowgen 4 5 6 is a tool for translating from TypeScript to Flow. It isn't perfect, and it's transparent about that, which is good to see. We just need this single file translated, and it's small, so that increases our chances of success. Run
flowgen libdef.d.ts. -
That output isn't exactly in the form that we want, though. We want to put this information in
flow-typed/remotedev-serialize_vx.x.x.jsfrom step 2, in this block:declare module 'remotedev-serialize' { declare module.exports: any; }Copy it into that block, in any case, deleting the
declare module.exports: any;line (we favor ES modules over CommonJS modules) and observe the errors. -
The minimal set of changes to get it working was
A) replace 'export' with 'declare export' 7
B) replace
typeof Immutablewithanyand remove the Immutable import. You can't import types from other libdefs in a libdef 8. -
Step 2 created a lot of extra stubs in case we wanted to make a libdef for every single file in
node_modules/remotedev-serialize. We never import directly from these other files, so it's fine to just put all the type information in a single libdef, as we did in the copy-and-paste in step 5. Delete those extra, unnecessary stubs.
react-native-webview at v7.6
The latest version FlowTyped has a libdef for is 6, unfortunately.
Ah, well. I made a best effort at replicating the types at
react-native-community/react-native-webview@c4001338c, tagged as
v7.6.0, the latest 7.x.
I used FlowType's react-native-webview v6 libdef as a starting
point, to match any conventions that may have been established after
the v5 libdef we were on before. Then, I ran the following in the
react-native-webview repo, which I had cloned:
git diff v6.8.0..v7.6.0 -- src/WebViewTypes.ts
I then went through the diff and did my best to apply each change, blending in with the local style. The most prominent example of this blending in was using, e.g.,
onHttpError?: WebViewHttpErrorEvent => mixed,
instead of
onHttpError?: (event: WebViewHttpErrorEvent) => void,
which would be valid Flow but wouldn't blend in with similar event handlers.
One choice that proved helpful was to not start at the top of the diff and work my way down, but to find changes to the major types that the Flow libdef needs to export, and start there, following through with any changes to auxiliary types that those changes depend on. There were many changes in the TypeScript that didn't affect anything that our libdef exports, and these were rightfully and automatically ignored with this approach, saving time.
Like with v5, though, the v6 libdef was lacking most of the JSDocs,
and several properties were needlessly in a different order than in
the TypeScript, so once I was basically familiar with the changes I
needed to take, I went through
react-native-community/react-native-webview@c4001338c and fixed
the ordering and copied over lots of comments.
A big remaining problem with this libdef can't currently be solved,
unfortunately. We can't import types from react-native, which we'd
want to do, e.g., to correctly express that the WebView component
can take all the props that the View component can. React Native has
a convenient type, ViewProps, for that, but there are open issues in
Flow and FlowTyped about not being able to import third-party types
into one's own libdefs that haven't been resolved. 9
Expo packages (made available through Unimodules)
We're starting to see a pattern developing with these, e.g.:
expo-apple-authenticationexpo-screen-orientation
Namely:
-
See what
node_modules/expo-name-of-package/build/index.d.tsdepends on; it's probably at least'./NameOfPackage'and'./NameOfPackage.types'.Assuming so, make a
declare module expo-name-of-packageblock and have it do what thatindex.d.tsdoes, maybedeclare module 'expo-name-of-package' { declare export * from 'expo-name-of-package/build/NameOfPackage' declare export * from 'expo-name-of-package/build/NameOfPackage.types' } -
Run
node_modules/expo-name-of-package/build/NameOfPackage.d.tsthrough Flowgen and paste the output into adeclare module 'expo-name-of-package/build/NameOfPackage'block. -
Run
node_modules/expo-name-of-package/build/PackageName.types'through Flowgen and paste the output into adeclare module 'expo-screen-orientation/build/ScreenOrientation.types'block. -
Make any necessary syntactic fixes based on error messages (in particular, replacing
exportwithdeclare exporteverywhere may be necessary) or adjustments to imports. You may only import from something that's been declared in that same file, withdeclare export1 2.
2: See discussion around https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/libdef.3A.20react-native-webview/near/896713.