第 3 节:其他问题
有时编写 React 不仅仅是关于 React 本身。虽然我们不关注 Redux 等其他库(有关更多信息,请参见下文),但以下是一些在使用 React + TypeScript 构建应用程序时需要注意的其他常见问题。
编写 TypeScript 库而不是应用程序
在使用 TypeScript 构建 React + TypeScript **应用程序**时,propTypes
似乎没有必要,但它们在编写可能被使用 JavaScript 工作的开发人员使用的**库**时仍然相关。
interface MyComponentProps {
autoHeight: boolean;
secondProp: number;
}
export class MyComponent extends React.Component<MyComponentProps, {}> {
static propTypes = {
autoHeight: PropTypes.bool,
secondProp: PropTypes.number.isRequired,
};
}
组件注释
TypeScript 使用 TSDoc,它是 TypeScript 的 JSDoc 变体。这对于编写组件库并在自动完成和其他工具(如 Docz PropsTable)中显示有用的描述非常方便。主要需要注意的是,在要注释的内容正上方的行中使用 /** YOUR_COMMENT_HERE */
语法。
interface MyComponentProps {
/** Description of prop "label".
* @default foobar
* */
label?: string;
}
/**
* General component description in JSDoc format. Markdown is *supported*.
*/
export default function MyComponent({ label = "foobar" }: MyComponentProps) {
return <div>Hello world {label}</div>;
}
命名空间组件
通常在创建类似的组件或具有父子关系的组件时,对组件使用命名空间很有用。可以通过使用 Object.assign()
轻松添加类型;
import { forwardRef } from "react";
const Input = (props: any) => <input {...props} />;
const Form = forwardRef<HTMLDivElement, any>(
({ children, ...otherProps }, ref) => (
<form {...otherProps} ref={ref}>
{children}
</form>
)
);
/**
* Exported components now can be used as `<Form>` and `<Form.Input>`
*/
export default Object.assign(Form, { Input: Input });
(由 @bryceosterhaus 贡献,请参阅 进一步讨论)
设计系统开发
我确实喜欢 Docz,它只需要 一行配置 即可接受 TypeScript。但是它比较新,还有一些粗糙的边缘(由于它仍然 < v1.0,因此有许多重大更改)
对于使用 Storybook 进行开发,请阅读我在这里编写的文档:https://storybook.org.cn/configurations/typescript-config/。这包括自动生成属性类型文档,非常棒 :)
从 Flow 迁移
您应该查看从 Flow 迁移的大型项目,以了解相关问题和技巧
实用库
- https://github.com/bcherny/flow-to-typescript
- https://github.com/Khan/flow-to-ts
- https://github.com/piotrwitek/utility-types
如果您在该领域有具体的建议,请提交 PR!
Prettier
TypeScript 的 Prettier 并没有什么真正的秘密。但是,在每次提交时运行 Prettier 是一个好主意!
$ yarn add -D prettier husky lint-staged
// inside package.json
{
//...
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"linters": {
"src/*.{ts,tsx,js,jsx,css,scss,md}": [
"prettier --trailing-comma es5 --single-quote --write",
"git add"
],
"ignore": ["**/dist/*, **/node_modules/*"]
}
},
"prettier": {
"printWidth": 80,
"semi": false,
"singleQuote": true,
"trailingComma": "es5"
}
}
将其与 ESlint 集成可能会出现问题。我们还没有在这方面写太多内容,如果您有强烈的意见,请贡献您的想法。 这是一个有用的 gist。
对于库作者,这在 tsdx 中为您设置好了。您可能还想查看更新的 https://ts-engine.dev/ 项目。
测试
是的,您可以测试您的类型!您不应该将其用于所有内容,但它可以帮助防止回归
- https://github.com/azz/jest-runner-tsc
- https://github.com/SamVerschueren/tsd
- https://github.com/ikatyang/dts-jest (演示)
- https://github.com/microsoft/dtslint (dtslint 简介)
使用非 TypeScript 库(编写您自己的 index.d.ts)
假设您想使用 de-indent
,但它没有类型或不在 DefinitelyTyped 上。您会收到类似这样的错误
[ts]
Could not find a declaration file for module 'de-indent'. '/Users/swyx/Work/react-sfc-loader/node_modules/de-indent/index.js' implicitly has an 'any' type.
Try `npm install @types/de-indent` if it exists or add a new declaration (.d.ts) file containing `declare module 'de-indent';` [7016]
因此,在项目的任何位置创建一个包含模块定义的 .d.ts
文件
// de-indent.d.ts
declare module "de-indent" {
function deindent(): void;
export = deindent; // default export
}
进一步讨论
还有其他技巧吗?请为此主题做出贡献! 我们在这里有一个包含一些引用的正在进行的问题。我们有更多讨论和示例 在此处的我们的问题中。
编译速度
编译大型 TS 项目可能会变慢。以下是一些技巧
- 我们有一个专门的仓库跟踪 TS 速度建议:https://github.com/typescript-cheatsheets/speed
- 使用 TS 3.0 项目引用
- 查看官方的 TS 性能 wiki 指南 - 请注意 Dan Rossenwasser 建议谨慎对待
- Webpack (查看 CRA diff)
- 设置
output.pathinfo = false
- 将
optimization.splitChunks
、optimization.removeAvailableModules
、optimization.removeEmptyChunks
设置为false
- 设置