I have a npm package of React components which are using flow for type-checking.
It would be useful for the users of my components to have access to my flow types. However at the moment I am compiling my code using Babel which strips all type information.
My project structure is as follows :
|
|- flowdecls
myTypes.js
| -components
- Component1
Component1.js
| - lib
- Component1.js (compiled using Babel)
- Component1.js.flow (created using flow-copy-source)
For example one of my types in myTypes.js
is
declare type DataItemIconType = {
iconElement: React$Element<React$ElementType>,
color?: string,
hoverColor?: string
}
which I would using in Component1
. For example one of the props of Component1
would be
iconList : Array<DataItemIconType>
I have already published several versions of my library of React components as an npm package without Flow and my components are being widely used. However I would really like to provide flow support.
In my most recent I tried using flow-copy-source as specified in this article (Authoring and publishing JavaScript modules with Flow) but users of my library still can't access my types.
How would I make a type such as DataItemIconType
available to someone using Component1
in my library ?
package.json
{
"name": "@company/react-common-components-build-template",
"version": "0.6.0",
"main": "./lib/index.js",
"private": true,
"engines": {
"node": ">=4.0.0"
},
"files": [
"lib"
],
"description": "Common component library",
"peerDependencies": {
"react": "16.10.0",
"react-dom": "16.10.0",
"prop-types": "15.7.2"
},
"dependencies": {
"@material-ui/core": "4.9.5",
"@material-ui/icons": "4.9.1",
"@material-ui/lab": "3.0.0-alpha.30",
"@material-ui/styles": "4.9.0",
"lodash": "4.17.15"
},
"devDependencies": {
"@babel/cli": "7.4.4",
"@babel/core": "7.6.0",
"@babel/node": "7.2.2",
"@babel/plugin-proposal-class-properties": "7.2.1",
"@babel/plugin-syntax-dynamic-import": "7.2.0",
"@babel/plugin-transform-object-assign": "7.2.0",
"@babel/plugin-transform-react-constant-elements": "7.6.0",
"@babel/plugin-transform-runtime": "7.6.2",
"@babel/preset-env": "7.4.2",
"@babel/preset-flow": "7.0.0",
"@babel/preset-react": "7.0.0",
"@babel/register": "7.0.0",
"@svgr/webpack": "4.3.2",
"@typescript-eslint/eslint-plugin": "^2.2.0",
"@typescript-eslint/parser": "^2.2.0",
"babel-eslint": "10.0.3",
"babel-jest": "24.9.0",
"babel-loader": "8.0.6",
"babel-plugin-named-asset-import": "0.3.4",
"babel-plugin-react-remove-properties": "0.3.0",
"babel-preset-react-app": "9.0.2",
"camelcase": "^5.2.0",
"case-sensitive-paths-webpack-plugin": "2.2.0",
"chokidar": "1.6.1",
"classnames": "2.2.6",
"cpx": "1.5.0",
"cross-env": "6.0.3",
"css-loader": "2.1.1",
"dotenv": "6.2.0",
"dotenv-expand": "5.1.0",
"enzyme": "3.10.0",
"enzyme-adapter-react-16": "1.15.1",
"enzyme-to-json": "3.4.3",
"eslint": "6.6.0",
"eslint-config-react-app": "5.0.2",
"eslint-loader": "3.0.0",
"eslint-plugin-flowtype": "3.13.0",
"eslint-plugin-flowtype-errors": "4.1.0",
"eslint-plugin-import": "2.18.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-react": "7.16.0",
"eslint-plugin-react-hooks": "^2.3.0",
"file-loader": "3.0.1",
"flow-bin": "0.113.0",
"flow-copy-source": "^2.0.9",
"flow-typed": "^2.6.2",
"fs-extra": "7.0.1",
"glob-gitignore": "1.0.14",
"hard-source-webpack-plugin": "^0.13.1",
"highlight": "^0.2.4",
"highlight.js": "^9.10.0",
"html-webpack-plugin": "4.0.0-beta.5",
"husky": "3.0.8",
"identity-obj-proxy": "3.0.0",
"is-wsl": "^1.1.0",
"jest": "24.9.0",
"jest-environment-jsdom-fourteen": "1.0.1",
"jest-enzyme": "^7.1.2",
"jest-resolve": "24.9.0",
"jest-watch-typeahead": "0.4.0",
"mini-css-extract-plugin": "0.9.0",
"npm-run-all": "4.0.2",
"optimize-css-assets-webpack-plugin": "5.0.3",
"pnp-webpack-plugin": "1.5.0",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-normalize": "7.0.1",
"postcss-preset-env": "6.7.0",
"postcss-safe-parser": "4.0.1",
"prettier": "1.19.1",
"react": "16.10.0",
"react-addons-test-utils": "15.5.1",
"react-app-polyfill": "^1.0.3",
"react-dev-utils": "10.2.0",
"react-docgen": "3.0.0",
"react-dom": "16.10.0",
"react-highlight": "^0.12.0",
"react-test-renderer": "16.10.0",
"resolve": "1.15.0",
"resolve-url-loader": "3.1.1",
"sass-loader": "8.0.2",
"semver": "6.3.0",
"style-loader": "1.0.0",
"terser-webpack-plugin": "2.3.4",
"ts-pnp": "1.1.5",
"url-loader": "2.3.0",
"webpack": "4.41.5",
"webpack-dev-server": "3.10.2",
"webpack-manifest-plugin": "2.2.0",
"workbox-webpack-plugin": "4.3.1"
},
"scripts": {
"prestart": "npm run gen:docs",
"start": "npm-run-all --parallel start:docs gen:docs-watch",
"start:docs": "node scripts/start.js",
"gen:docs": "node scripts/generateComponentData.js",
"gen:docs-watch": "npm run gen:docs -- --watch",
"build:docs": "node scripts/build.js",
"test": "node scripts/test.js",
"predeploy:docs": "npm run build:docs",
"flow": "flow",
"lint": "eslint src --debug",
"lint:flow-typed": "flow-typed install --ignoreDeps dev",
"build:images": "cpx \"./src/components/images/**/*.*\" ./lib/images",
"prebuild:common-components-lib": "rimraf lib",
"build:common-components-lib": "npm-run-all --parallel build:components build:utils build:images build:copy-files build:copyflowsource",
"build:components": "cross-env NODE_ENV=production BABEL_ENV=cjs babel ./src/components --out-dir ./lib/ --ignore spec.js",
"build:utils": "cross-env NODE_ENV=production BABEL_ENV=cjs babel src/components/utils --out-dir ./lib/utils --ignore spec.js",
"build:copyflowsource": "flow-copy-source ./src/components ./lib ",
"build:copy-files": "node scripts/copyBuildFiles.js",
"prettier:changed": "node ./scripts/prettier.js",
"prettier:all": "node ./scripts/prettier.js write",
"format-check": "prettier --check \"./src/**/*.{js,test.js,spec.js}\""
},
"publishConfig": {
"registry": "http://srv-ie-nexus/repository/npm-hosted/"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"jest": {
"roots": [
"<rootDir>/src/components"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"setupFiles": [
"react-app-polyfill/jsdom"
],
"setupFilesAfterEnv": [
"<rootDir>/jest-test-setup.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"testEnvironment": "jest-environment-jsdom-fourteen",
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$"
],
"modulePaths": [],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node"
],
"watchPlugins": [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
]
}
}
Flow will automatically look for adjecent module.js.flow
declarations files, if present.
For example, if you have a main field that points to dist/index.js
, then adding dist/index.js.flow
to your package's outputs will have it picked up by the user's language server.
I don't think flow has a solution to this yet. But I was in the same boat as you.
Pretty much the reason your consumers aren't able to use your package types are because they read global types from their .*/flow-typed/*
not your one which when they install your package will be in .*/node_modules/@company/react-common-components-build-template
. It has nothing to do with any package.json settings.
You have two options though to ship your package with types.
Either you put them as part of your src
code and allow them to import it, which means your types won't be global anymore and you need to import the types you want to use within your source code. But this means so can you consumers.
Or keep them in your flowdecls
and ensure they're published. Once they are, your users will have to copy your type defs into their flow-typed
dir, which will now make them global within their project also.
You can add something like the following into your README to give users some insight:
react-common-components-build-template
also uses global type definitions internally. If you would like to take advantage of this, you can copy /node_modules/@company/react-common-components-build-template/flowdecls/myTypes.js
to your local flow-typed directory. It's probably a good idea to do a copy once per version upgrade so you stay in-sync with the latest changes which you can do via npm scripts.
"scripts": {
// ...
"postinstall": "cp /node_modules/@company/react-common-components-build-template/flowdecls/myTypes.js flow-typed"
},
The second option is actually what I've gone with, and the above is what I have in my repo. As a side note, I would recommend though that you rename your dir to flow-typed
and your types file to something like react-common-components-build-template.js
so that when the copy process happens, people don't wonder what myTypes.js
is used for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With