在React中Typescript帮助我们在编译前发现下列错误,而不必等待运行时:

  • 试图传递一个额外的不想要的prop给组件
  • 忘记传递必须的prop给组件
  • 传递错误类型的prop给组件

Create React App with TypeScript

使用create-react-app创建项目, 只需加—template参数

  1. npx create-react-app my-app --template typescript

可以看到.js和.jsx文件都变成了.ts和.tsx文件
根目录还有tsconfig.json文件, 将其中的allowJS配置设为false,除非你想同时用js和ts
create-react-app默认安装了esLint, 新建.eslintrc文件,添加配置如下

  1. {
  2. "env": {
  3. "browser": true,
  4. "es6": true,
  5. "jest": true
  6. },
  7. "extends": [
  8. "eslint:recommended",
  9. "plugin:react/recommended",
  10. "plugin:@typescript-eslint/recommended"
  11. ],
  12. "plugins": ["react", "@typescript-eslint"],
  13. "settings": {
  14. "react": {
  15. "pragma": "React",
  16. "version": "detect"
  17. }
  18. },
  19. "rules": {
  20. "@typescript-eslint/explicit-function-return-type": 0,
  21. "@typescript-eslint/explicit-module-boundary-types": 0
  22. }
  23. }

因为基本上所有 React 组件都返回一个JSX.Element 类型或null 类型,所以我们通过将规则 explicit-function-return-type设为0(禁用)来稍微放松默认的lint规则,这样我们就不需要在所有地方显式写出函数返回类型 。
现在我们需要让我们的 linting 脚本也来解析 *.tsx文件,在package.json中添加lint命令

  1. "scripts": {
  2. "start": "react-scripts start",
  3. "build": "react-scripts build",
  4. "test": "react-scripts test",
  5. "eject": "react-scripts eject",
  6. "lint": "eslint './src/**/*.{ts,tsx}'"
  7. },

window系统要用双引号:”lint”: “eslint \”./src/*/.{ts,tsx}\””
使用命令npm start启动应用

React components with TypeScript

为props定义类型

  1. interface WelcomeProps {
  2. name: string;
  3. }
  4. const Welcome = (props: WelcomeProps) => {
  5. return <h1>Hello, {props.name}</h1>;
  6. };
  7. const element = <Welcome name="Sara" />;
  8. ReactDOM.render(element, document.getElementById("root"));

也可以用简洁一点的方式

  1. const Welcome = ({ name }: { name: string }) => (
  2. <h1>Hello, {name}</h1>
  3. );

Deeper type usage

  1. // 声明类型
  2. interface CoursePartBase {
  3. name: string
  4. exerciseCount: number
  5. type: string
  6. }
  7. interface CourseNormalPart extends CoursePartBase {
  8. type: 'normal'
  9. description: string
  10. }
  11. interface CourseProjectPart extends CoursePartBase {
  12. type: 'groupProject'
  13. groupProjectCount: number
  14. }
  15. interface CourseSubmissionPart extends CoursePartBase {
  16. type: 'submission'
  17. description: string
  18. exerciseSubmissionLink: string
  19. }
  20. type CoursePart = CourseNormalPart | CourseProjectPart | CourseSubmissionPart
  21. // 使用类型
  22. const courseParts: CoursePart[] = [
  23. {
  24. name: 'Fundamentals',
  25. exerciseCount: 10,
  26. description: 'This is the leisured course part',
  27. type: 'normal',
  28. },
  29. {
  30. name: 'Advanced',
  31. exerciseCount: 7,
  32. description: 'This is the harded course part',
  33. type: 'normal',
  34. },
  35. {
  36. name: 'Using props to pass data',
  37. exerciseCount: 7,
  38. groupProjectCount: 3,
  39. type: 'groupProject',
  40. },
  41. {
  42. name: 'Deeper type usage',
  43. exerciseCount: 14,
  44. description: 'Confusing description',
  45. exerciseSubmissionLink: 'https://fake-exercise-submit.made-up-url.dev',
  46. type: 'submission',
  47. },
  48. ]

使用 switch case, typescript能根据每个联合类型都有的相同属性作为标识符来判断这个类型里拥有的其他属性
image.png
在switch中使用穷举类型检查,可以防止遗漏

  1. /**
  2. * Helper function for exhaustive type checking
  3. */
  4. const assertNever = (value: never): never => {
  5. throw new Error(
  6. `Unhandled discriminated union member: ${JSON.stringify(value)}`
  7. );
  8. };
  1. default:
  2. return assertNever(coursepart);

如果在多个位置使用interface声明相同名字的类型,它们会合并,如果使用type做相同的事则会报错
typescript推荐大多数时候都使用interface

Working with an existing codebase

The more code you read the better you’re going to be at it. You will read more code than you’re going to produce.

当第一次接手一个项目代码时,应先对项目的约定和结构有个全面的了解,先看根目录的README.md文件,如果没有,则看package.json文件,浏览文件夹的结构,如果是TS代码,查看types.ts文件也有帮助

State Handling

我们使用React Hooks useContext and useReducer做轻量级状态管理,不需要使用第三方库Redux