2023-02-11 19:06:59    67    0    0

在tsx下使用

默认情况下,我们不能在函数组件上使用 ref 属性,因为它们没有实例。

如果要在函数组件中使用 ref,可以使用 forwardRef 包裹组件函数使用(可与 useImperativeHandle 结合使用)。

被 forwardRef 包裹的组件函数除 props,还要多传入第二个参数:ref,即从外部传入的 ref。

useImperativeHandle 接收三个参数,第一个是 forwardRef 传入的 ref;第二个参数是 handle 函数,返回要向外暴露的值,通常是对象;第三个参数是依赖数组,根据依赖变化执行更新,非必需参数。

  1. import { useRef, forwardRef, Ref, useImperativeHandle, ElementRef, useEffect } from "react";
  2. // 组件,有两种定义类型的方式
  3. // 组件1,一种是使用 forwardRef 的泛型
  4. // forwardRef 泛型第一个参数是 Ref 类型,
  5. // 第二个参数是 props 类型,不传时默认类型为{},
  6. // 注意,forwardRef 泛型与内部包裹函数的参数顺序恰恰相反,易造成歧义
  7. const Component1 = forwardRef<HTMLInputElement, {}>((props, ref) => <input ref={ref} />);
  8. // 组件2,另一种是是在函数参数上直接定义类型, **该方式验证有效**
  9. // 注意,在函数参数上定义类型时,ref 参数类型需要使用Ref泛型包裹,而 forwardRef 泛型则不需要
  10. const type useImperativeHandle返回的类型 = React.Ref<{
  11. sayHello: () => void
  12. }>
  13. const Component2 = forwardRef(
  14. // ref 类型使用了 Ref 泛型包裹
  15. (props: {}, ref: useImperativeHandle返回的类型) => {
  16. // ref 为第一个参数,返回带有 sayHello 方法对象的函数为第二个参数
  17. us
2023-01-07 16:11:49    15    0    0

包含功能

  • typescript
  • stylelint
  • prettier
  • eslint
  • husky
    • git钩子
  • styled-components
  • react-app-rewired
    • 调整 create-react-app webpack 配置而不使用 'eject' 并且不创建 react-scripts 的分支。
    • 没有“无配置”限制的 create-react-app 的所有好处。您可以根据需要添加插件、加载程序。
  • customize-cra 依赖于react-app-rewired, 您需要安装它才能customize-cra工作, 增加babel-plugin-import配置动态引入Antd组件
  • babel-plugin-import
    • babel 模块化导入插件,兼容antdantd-mobilelodashmaterial-ui等。
  • antd
  • ahooks

安装create-react-app

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

或者

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

安装antd和定制化Create-React-App项目的两个包

  1. npm install antd --save
  2. npm install babel-plugin-import react-app-rewired customize-cra --save-dev

根目录创建config-overrides.js,用customized-cra来增加babel-plugin-import配置动态引入Antd组件

  1. const { override, fixBabelImports } = require('customize-cra');
  2. module.exports = override(fixBabelImports('import', {
  3. libraryName: 'antd',
  4. lib
2023-01-07 07:40:59    6    0    0
  1. // scanMixin.js
  2. export default {
  3. data() {
  4. return {
  5. code: '',
  6. lastTime: '',
  7. nextTime: '',
  8. lastCode: '',
  9. nextCode: '',
  10. dtmainId: '',
  11. };
  12. },
  13. activated() {
  14. window.addEventListener('keypress', this.scanEventHandler, false);
  15. },
  16. beforeDestroy() {
  17. window.removeEventListener('keypress', this.scanEventHandler, false);
  18. },
  19. deactivated() {
  20. window.removeEventListener('keypress', this.scanEventHandler, false);
  21. },
  22. methods: {
  23. scanEventHandler(e) {
  24. if (window.event) { // IE
  25. this.nextCode = e.keyCode;
  26. } else if (e.which) { // Netscape/Firefox/Opera
  27. this.nextCode = e.which;
  28. }
  29. if (e.which === 13) { // 键盘回车事件
  30. if (this.code.length < 3) return; // 扫码枪的速度很快,手动输入的时间不会让code的长度大于2,所以这里不会对扫码枪有效
  31. console.log('扫码结束。');
  32. console.log('条形码:', this.code);
  33. this.parseQRCode(this.code); // 获取到扫码枪输入的内容,做别的操作
  34. this.code = '';
  35. this.lastCode
2022-12-25 10:10:29    8    0    0

Type ‘undefined’ is not assignable to type ‘Function’.

nullundefined 是其它类型(包括 void)的子类型,可以赋值给其它类型(如:数字类型),赋值后的类型会变成 nullundefined
使用第三方/自己的代码声明里没有定义 null | undefined, 可强制转换值的类型

语法

  1. <类型>值

或者(tsx中只能使用这种方式)

  1. as 类型
2022-12-25 09:50:19    15    0    0
2022-12-25 07:00:32    6    0    0
  1. 如果你有module.tsmodule.d.ts在同一个文件夹中(重名),编译器会跳过module.d.ts文件,所以你的声明将不被考虑。重命名d.ts文件或将其移动到另一个文件夹。如果您有合适的模块,这种方法很好,但是如果您想在模块之间共享类型,最好使用import .. from ..
  2. .d.ts文件中有importexport,它就会成为一个模块,并且该模块中的所有内容都必须由使用者随后导入。

声明全局到单独一个文件

  • 创建一个 node_modules/@types/foo/index.d.ts 文件,存放 foo 模块的声明文件。不太建议用这种方案,一般只用作临时测试。
  • 创建一个 types 目录,专门用来管理自己写的声明文件,将 foo 的声明文件放到 types/foo/index.d.ts 中。这种方式需要配置下 tsconfig.json 中的 pathsbaseUrl 字段。

    1. // path/to/project
    2. ├── src
    3. | └── foo
    4. | └── index.ts
    5. ├── types
    6. | └── foo
    7. | └── index.d.ts
    8. └── tsconfig.json
    9. // tsconfig.json
    10. {
    11. "compilerOptions": {
    12. "module": "commonjs",
    13. "baseUrl": "./",
    14. "paths": {
    15. "*": ["types/*"]
    16. }
    17. }
    18. }

声明模块到全局

  • 同上
  • declare
  1. declare namespace 模块名称 { // 模块名称加了引号为外部模块, 不加为作用域
  2. // 从TS2.9开始,我们可以使用import()语法
  3. type User = import('./user').User;
  4. export interface Request {
  5. user: User;
  6. target: User;
  7. friend: User;
  8. }
  9. export class SuperUser implements User {
2022-12-24 12:19:50    116    0    0

定义了一个 EitherOr 的类型来处理这种情况

  1. type FilterOptional<T> = Pick<
  2. T,
  3. Exclude<
  4. {
  5. [K in keyof T]: T extends Record<K, T[K]> ? K : never
  6. }[keyof T],
  7. undefined
  8. >
  9. >
  10. type FilterNotOptional<T> = Pick<
  11. T,
  12. Exclude<
  13. {
  14. [K in keyof T]: T extends Record<K, T[K]> ? never : K
  15. }[keyof T],
  16. undefined
  17. >
  18. >
  19. type PartialEither<T, K extends keyof any> = {
  20. [P in Exclude<keyof FilterOptional<T>, K>]-?: T[P]
  21. } & { [P in Exclude<keyof FilterNotOptional<T>, K>]?: T[P] } & {
  22. [P in Extract<keyof T, K>]?: undefined
  23. }
  24. type Objects = {
  25. [name: string]: any
  26. }
  27. type EitherOr<O extends Objects, L extends string, R extends string> = (
  28. | PartialEither<Pick<O, L | R>, L>
  29. | PartialEither<Pick<O, L | R>, R>
  30. ) &
  31. Omit<O, L | R>

使用例子

  1. // a、b二选一,并且必须传递一个
  2. type RequireOne = EitherOr<
  3. {
  4. a: number;
  5. b: string;
  6. },
  7. 'a',
  8. 'b'
  9. >;
  10. // a、b二选一,或者都不传
  11. type RequireOneOrEmpty = EitherOr<
  12. {
  13. a?: number;
  14. b?: string;
  15. },
  16. 'a',
  17. 'b'
  18. >;

实际应用

  1. interfac
2022-12-23 13:32:49    4    0    0

1. 接口(interface)

1. interface

接口主要用于类型检查,他只是一个结构契约,定义了具有相似的名称和类型的对象结构。除此之外,接口还可以定义方法和事件

An interface is primarily used for type checking; it is simply a structural contract that defines the structure of objects with similar names and types. In addition, interfaces can define methods and events

2. 类型别名(Type Alias)

不同与intetrface只能定义对象类型,type声明任何类型,包括定义基础类型,联合声明或交叉类型

差异点

  1. 定义类型范围
    interface只能定义对象类型,而type声明可以声明任何类型,包括基础类型、联合类型或交叉类型

    1. //基本数据类型
    2. type person = string
    3. //联合类型
    4. interface Dog {
    5. name: string;
    6. }
    7. interface Cat {
    8. age: number;
    9. }
    10. type animal = Dog | Cat
    11. //元组类型
    12. interface Dog {
    13. name: string;
    14. }
    15. interface Cat {
    16. age: number;
    17. }
    18. type animal = [Dog, Cat]
    19. // 交叉类型
    20. type Person = {
    21. name: string
    22. }
    23. type User = Person & { age: number }
    24. // type & interface
    25. interface Person {
    26. name: string
    27. }
    28. type User = {age: number} & Person
  2. 扩展性
    接口可以extends、implements,从而扩展多个接口或类。类型没有扩展功能

    1. // interface extends interface
    2. interface Person {
    3. name: string
    4. }
    5. interface User extends Person {
2022-12-14 12:37:38    4    0    0
  • 只需进入项目文件夹下的 .git文件中,显示隐藏文件夹删除index.lock文件即可。
2022-08-31 02:57:44    22    0    0
  1. <!-- 空页面,负责中转到目标页面 -->
  2. <template>
  3. <div></div>
  4. </template>
  5. <script>
  6. export default {
  7. name: 'refresh',
  8. data () {
  9. return {}
  10. },
  11. beforeRouteEnter (to, from, next) {
  12. next(vm => {
  13. const data = {
  14. ...from,
  15. query: { ...from.query, ...to.query },
  16. params: { ...from.params, ...to.params }
  17. }
  18. vm.$router.replace(data)
  19. })
  20. }
  21. }
  22. </script>
  1. this.$router.push({
  2. name: routerName,
  3. params: { aa: 2 }, // params不在浏览器url里显示,刷新页面参数消失
  4. })
3/18