跳至主要内容

第 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>;
}

在 TypeScript Playground 中查看

有要补充的吗?提交问题.

命名空间组件

通常在创建类似的组件或具有父子关系的组件时,对组件使用命名空间很有用。可以通过使用 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 });

在 TypeScript Playground 中查看

(由 @bryceosterhaus 贡献,请参阅 进一步讨论

有要补充的吗?提交问题.

设计系统开发

我确实喜欢 Docz,它只需要 一行配置 即可接受 TypeScript。但是它比较新,还有一些粗糙的边缘(由于它仍然 < v1.0,因此有许多重大更改)

对于使用 Storybook 进行开发,请阅读我在这里编写的文档:https://storybook.org.cn/configurations/typescript-config/。这包括自动生成属性类型文档,非常棒 :)

有要补充的吗?提交问题.

从 Flow 迁移

您应该查看从 Flow 迁移的大型项目,以了解相关问题和技巧

实用库

如果您在该领域有具体的建议,请提交 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/ 项目。

测试

是的,您可以测试您的类型!您不应该将其用于所有内容,但它可以帮助防止回归

使用非 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 项目可能会变慢。以下是一些技巧