TypeScript + React:元素类型无效:需要一个字符串(对于内置组件)
TypeScript + React: Element type is invalid: expected a string (for built-in components)
我意识到有几个问题与这个错误有关,但据我所知这是一个独特的情况,与不正确的 import
语句无关。
我正在使用 TypeScript
和 webpack
构建一个 React
组件库。
我的目录结构:
- src
- index.ts
- components
- Button
- Button.tsx
- index.ts
- Button.css
- Button.d.css (generated by webpack plugin)
- package.json
- tsconfig.json
- webpack.config.js
- postcss.config.js
我的tsconfig.json
:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"module": "es2015",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": false,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"outDir": "dist",
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"declaration": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"build",
"dist",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts",
"**/*/*.test.ts",
"examples"
]
}
我的webpack.config.js
:
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js"
},
mode: "development",
module: {
rules: [
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader",
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'typings-for-css-modules-loader',
options: {
modules: true,
namedExport: true,
banner: "/* This file is generated during the webpack build. Please do not edit/remove. */",
localIdentName: '[name]__[local]'
}
},
{
loader: 'postcss-loader',
options: {
config: {
path: './postcss.config.js'
}
}
}
]
},
{
test: /\.(jpg|png|gif|svg)$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[ext]"
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
devtool: "source-map",
resolve: {
extensions: [".js", ".ts", ".tsx", ".css"]
}
};
我的postcss.config.js
:
module.exports = {
modules: true,
plugins: [
require('precss'),
require('postcss-simple-vars'),
require('autoprefixer'),
require('postcss-nested'),
]
}
src/index.ts
就是:
import { Button } from './components/Button';
export {
Button,
};
src/components/Button/index.ts
:
import Button from './Button';
export { Button };
和src/components/Button/Button.tsx
:
import * as React from 'react';
import { ReactNode } from 'react';
import { Link } from 'react-router-dom';
import * as styles from './Button.css';
export interface IButtonPropTypes {
onClick?: React.MouseEventHandler<any>;
label: string;
children?: ReactNode[] | string;
kind?: 'link' | 'action';
style?: { [key: string]: string };
href?: string;
target?: string;
className?: string;
}
export default function Button({
onClick,
label,
children,
kind = 'action',
style = {},
href,
target,
className,
}: IButtonPropTypes) {
const text = label || children;
const kindStyle = styles[kind] || '';
const classes = className || '';
if (href) {
return (
<Link
className={`${style.btn} ${kindStyle} ${classes}`}
to={href}
target={target}
onClick={onClick}
style={style}
>
<span className={style.background} />
<span>{text}</span>
</Link>
);
}
return (
<button className={`${style.btn} ${kindStyle}`} onClick={onClick} style={style}>
<div>{text}</div>
</button>
);
}
我的 dist
文件夹在 运行 webpack
之后看起来像:
- dist
- index.js
- index.js.map
- index.d.ts
- main.css
- main.css.map
- components
- Button
- Button.d.ts
- index.d.ts
和 dist/index.js
似乎被 webpack
正确编译。在 package.json
中,我有:
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"]
在 运行 yarn link
之后,我在独立应用程序中导入并使用我的 Button
组件,如下所示:
import { Button } from 'my-components';
class App extends React.Component {
render() {
return (
<div className="App">
<Button label="click me" />
</div>
);
}
}
export default App;
并收到以下错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got:
undefined. You likely forgot to export your component from the file
it's defined in, or you might have mixed up default and named imports.
Check the render method of `App`.
如果我删除 Button
组件,App
将无任何错误地呈现。
通过将一次性模块发布到 npm
进行测试会产生相同的错误。
此外,如果有人对捆绑此库的更好方法有任何建议,我很乐意听取他们的意见,因为这是我第一次使用 postcss
。
看来您在 index.ts
中导入时犯了一个小错误。由于它是默认导出,因此不应使用大括号。
import Button from './components/Button';
事实证明,这是因为我的 webpack
配置有问题。将以下行添加到 output
修复了错误:
output: {
. . .
library: "opentok-ux-components",
libraryTarget: 'umd',
umdNamedDefine: true
},
我意识到有几个问题与这个错误有关,但据我所知这是一个独特的情况,与不正确的 import
语句无关。
我正在使用 TypeScript
和 webpack
构建一个 React
组件库。
我的目录结构:
- src
- index.ts
- components
- Button
- Button.tsx
- index.ts
- Button.css
- Button.d.css (generated by webpack plugin)
- package.json
- tsconfig.json
- webpack.config.js
- postcss.config.js
我的tsconfig.json
:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"module": "es2015",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": false,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"outDir": "dist",
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"declaration": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"build",
"dist",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts",
"**/*/*.test.ts",
"examples"
]
}
我的webpack.config.js
:
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js"
},
mode: "development",
module: {
rules: [
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader",
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'typings-for-css-modules-loader',
options: {
modules: true,
namedExport: true,
banner: "/* This file is generated during the webpack build. Please do not edit/remove. */",
localIdentName: '[name]__[local]'
}
},
{
loader: 'postcss-loader',
options: {
config: {
path: './postcss.config.js'
}
}
}
]
},
{
test: /\.(jpg|png|gif|svg)$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[ext]"
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
devtool: "source-map",
resolve: {
extensions: [".js", ".ts", ".tsx", ".css"]
}
};
我的postcss.config.js
:
module.exports = {
modules: true,
plugins: [
require('precss'),
require('postcss-simple-vars'),
require('autoprefixer'),
require('postcss-nested'),
]
}
src/index.ts
就是:
import { Button } from './components/Button';
export {
Button,
};
src/components/Button/index.ts
:
import Button from './Button';
export { Button };
和src/components/Button/Button.tsx
:
import * as React from 'react';
import { ReactNode } from 'react';
import { Link } from 'react-router-dom';
import * as styles from './Button.css';
export interface IButtonPropTypes {
onClick?: React.MouseEventHandler<any>;
label: string;
children?: ReactNode[] | string;
kind?: 'link' | 'action';
style?: { [key: string]: string };
href?: string;
target?: string;
className?: string;
}
export default function Button({
onClick,
label,
children,
kind = 'action',
style = {},
href,
target,
className,
}: IButtonPropTypes) {
const text = label || children;
const kindStyle = styles[kind] || '';
const classes = className || '';
if (href) {
return (
<Link
className={`${style.btn} ${kindStyle} ${classes}`}
to={href}
target={target}
onClick={onClick}
style={style}
>
<span className={style.background} />
<span>{text}</span>
</Link>
);
}
return (
<button className={`${style.btn} ${kindStyle}`} onClick={onClick} style={style}>
<div>{text}</div>
</button>
);
}
我的 dist
文件夹在 运行 webpack
之后看起来像:
- dist
- index.js
- index.js.map
- index.d.ts
- main.css
- main.css.map
- components
- Button
- Button.d.ts
- index.d.ts
和 dist/index.js
似乎被 webpack
正确编译。在 package.json
中,我有:
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"]
在 运行 yarn link
之后,我在独立应用程序中导入并使用我的 Button
组件,如下所示:
import { Button } from 'my-components';
class App extends React.Component {
render() {
return (
<div className="App">
<Button label="click me" />
</div>
);
}
}
export default App;
并收到以下错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got:
undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `App`.
如果我删除 Button
组件,App
将无任何错误地呈现。
通过将一次性模块发布到 npm
进行测试会产生相同的错误。
此外,如果有人对捆绑此库的更好方法有任何建议,我很乐意听取他们的意见,因为这是我第一次使用 postcss
。
看来您在 index.ts
中导入时犯了一个小错误。由于它是默认导出,因此不应使用大括号。
import Button from './components/Button';
事实证明,这是因为我的 webpack
配置有问题。将以下行添加到 output
修复了错误:
output: {
. . .
library: "opentok-ux-components",
libraryTarget: 'umd',
umdNamedDefine: true
},