Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript 开发总结 #58

Open
chenxiaochun opened this issue Jul 31, 2018 · 0 comments
Open

TypeScript 开发总结 #58

chenxiaochun opened this issue Jul 31, 2018 · 0 comments

Comments

@chenxiaochun
Copy link
Owner

chenxiaochun commented Jul 31, 2018

image

最近一段时间使用 TypeScript,对遇到的问题做一些总结:

如何解决antd@Form.Create()修饰器无法使用的问题

一般我们会这样使用antd@Form.create()修饰器:

@Form.create()
class Test{}

但它可能会提示下面的类型错误:

Unable to resolve signature of class decorator when called as an expression.
Type 'ComponentClass<RcBaseFormProps & Pick<IProps, "store">, any>' is not assignable to type 'typeof Test'.
Property 'onChange' is missing in type 'Component<RcBaseFormProps & Pick<IProps, "store">, any, any>' but required in type 'Search'.

解决办法就是将修饰器改成使用函数调用的方式:

class Test{}
Form.create()(Test)

antd 官方解释:ant-design/ant-design#6489

如何解决以下提示store类型缺失的问题

Property 'store' is missing in type '{}' but required in type 'Readonly<RcBaseFormProps & Pick<IProps, "store">>'.

假如我有一个Search.tsx,它的源码大概是这样的:

import rollbackEdit from 'store/rollbackEdit'

interface IProps {
  store: {
    rollbackEdit: RollbackEditStore
  }
  form: WrappedFormUtils
}

@inject('store')
@observer
class Search extends React.Component<IProps> {
  public store: RollbackEditStore
  constructor(props: IProps) {
    super(props)
    const {
      store: { rollbackEdit },
    } = this.props
    this.store = rollbackEdit
  }

  public onChange = (value: SelectValue) => {
    const { form } = this.props
    this.store.setType(value)
    this.store.setList([])
    form.setFieldsValue({
      id: undefined,
    })
  }

  public render() {
    ...
  }
}

export default Form.create()(Search)

之所以会有最上面的错误类型提示,是因为Search组件的IProps中定义了store这个类型是必须的。但是,在constructor中引用this.props中的store时,却无法引用到它。

解决此问题,有两种方法。

第一种方法:

  1. 去掉construct中对store的引用
  2. 在类方法中针对this.store的引用都改成const { rollbackEdit } = this.props.store!。最后的叹号表示忽略去掉前面引用中的nullundefined
  3. IProps的定义改成如下的样子。没错儿,只是将store:改成了store?:
interface IProps {
  store?: {
    rollbackEdit: RollbackEditStore
  }
  form: WrappedFormUtils
}

第二种方法:

如果使用第一种方法,觉得改动量太大,有些麻烦。那么可以尝试下面这个方法。它既然提示在组件的props上不到store这个类型定义,那我们在调用Search组件的地方,给它的props传入store不就可以了。

比如,在index.tsx中:

const store = {
  rollbackEdit,
}

const RollbackEdit = () => (
  <Search store={store} />
  <List />
)

如何解决普通类中的方法定义必须被初始化的问题

我们定义了一个List组件:

class List {
  fetchList: () => void
}
Property 'fetchList' has no initializer and is not definitely assigned in the constructor.

tslint 就会提示你fetchList必须进行初始化。这时,最简单的解决方法可以去这样定义fetchList方法:

class List {
  fetchList!: () => void
}

fetchList后面加了一个叹号。但是,如果每次都这样写,好像有点儿麻烦。那可以在 tslint 配置文件中添加一条配置:"strictPropertyInitialization": false

这样看似解决了问题,但其实并不严谨。因为一个方法如果只是被定义了,并没有进行任何实现。是不应该写在普通类里的,而应该把它抽离到一个抽象类中,然后由普通类来继承它就可以了。所以,我们的代码大概应该改成这样:

abstract class AList {
  fetchList: () => void
}

class class List extends AList{}

这样就不会有任何验证错误了,而且更符合代码的编写规范。

如何解决 TypeScript 引起的 webpack split chunk 失效问题

我们的项目代码是从 jsx 逐渐过渡到 tsx 的。在将router.jsx改为router.tsx之后,发现 webpack split chunk 就失效了。

通过 google 搜索发现了 webpack 官方的这个帖子:webpack/webpack#5703

它的解决办法是直接在 tsconfig.json 配置中将module: "commonjs"改为"module": "esnext"。但是在我的 webpack 配置文件中又引用了很多以 commonjs 规范编写的组件。最终经过权衡,解决办法就是在 webpack 的ts-loader中配置一下这个选项,这样只会影响编译时的代码环境,而不会影响当前的源代码环境。

options: {
    compilerOptions: {
        module: "esnext",
    },
},

变量导出不能作为一个类型,即使这个变量是从一个 class 赋值而来

// A.ts
class A {}
const A1 = A
export A1

// B.ts
import { A1 } from './A'

看上面代码示例,我定义一个 class A,然后把它赋值给了 A1,并进行了导出。那么在 B 文件中我将 A 导入,可以作为一个类型定义吗?抱歉,不行。如果想使用 A 的类型定义,必须直接将 class A 本身导出才可以。

// A.ts
export class A {}

// B.ts
import { A1 } from './A'

如何定义高阶组件的children类型

interface IProps {
  children?: React.ReactNode
}

const CardTitle = ({ children }: IProps) => (
  {children || null}
)

React 的类型定义文件中对ReactNode的定义是:

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

如何让 vim ale tslint 忽略对 node_modules 下的文件检查

我发现即使在tslint.jsontsconfig.json中配置了以下参数,tslint 依然会顽固的会对 node_modules 中的 ts 文件进行检查,怎么也忽略不了。

{
  "exclude": ["node_modules"]
}

解决这个问题的第一个方法是修改 ale 的配置,直接在.vimrc中添加以下配置:

let g:ale_pattern_options = {
\   'node_modules': {'ale_enabled': 0},
\}

解决问题的第二个办法:

在 vim 中使用:ALEInfo查看当前文件的信息,发现这个文件被打开之后,是处于一个临时目录中:

/var/folders/bk/m7z1498j1dg3vx83lvy0v4vr0000gn/T/nvimzuNNoK/2/Form.d.ts

因此,也就导致了在 tslint 的配置文件中添加忽略node_modules是不起使用的。所以应该在配置文件中添加这个临时目录才行。这里还要注意,在 linux 或者 mac 系统中显示的临时目录不一定是一样的:

{
  "exclude": ["node_modules", "/var/folders/**"]
}

此问题,只会发生于 vim 中。如果你用的是 vscode 则不必担心。

@chenxiaochun chenxiaochun changed the title TypeScript 踩坑记录 TypeScript 开发总结 Mar 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant