TypeScript 开发总结

最近一段时间使用 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 官方解释:https://github.com/ant-design/ant-design/issues/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时,却无法引用到它。
解决此问题,有两种方法。
第一种方法:
- 去掉
construct中对store的引用 - 在类方法中针对
this.store的引用都改成const { rollbackEdit } = this.props.store!。最后的叹号表示忽略去掉前面引用中的null和undefined值 - 将
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 官方的这个帖子:https://github.com/webpack/webpack/issues/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.json和tsconfig.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 则不必担心。