大家好,我是俊宁,今天整理博客时翻到这么一篇去年翻译的文章,现在读来仍不过时,遂与大家分享。
随着时间的推移,TypeScript 改进了 defaultProps
相关的类型检查。本文将讲述最新的用法和旧版本中的用法以及一些问题。
TypeScript 3.0 以上
TypeScript 特意添加了对 defaultProps 的支持以此让类型检查符合你的预期:
import React from 'react'
import { Text } from 'react-native'
interface Props {
foo: string;
bar: string;
}
export default Hello extends React.Component<Props, {}> {
public static defaultProps = {
foo: "default"
}
public render() {
const { bar, foo } = this.props
return (
<Text>{ bar }, { foo.toUpperCase() }</Text>
)
}
}
Hello 这个组件可以在不传递 foo
属性的情况下渲染、编译正常:
<Hello bar="Hello" />
注意
- 尽管
foo
不是必须的,但是我们并没有把它被标记为可选的(例如foo?: string
)。标记为可选的意味着它可能是undefined
,但是实际上因为defaultProps
提供了默认值,它绝对不可能变成undefined
。 defaultProps
没有明确的类型声明。它的类型是由编译器推断的。- 需要
@types/react
版本在16.4.11
以上
TypeScript 2.1 到 3.0
你可以使用 TypeScript 的 Partial type
特性,这意味着当前的接口只会实现被包裹的接口的一部分,这样我们可以随意拓展 defaultProps
而不需要改其他任何地方。
import React from 'reac'
import { Text } from 'react-native'
interface Props {
foo?: string;
bar: number;
}
export default class MyComponent extends React.Component<Props, {}> {
static defaultProps: Partial<Props> = {
foo: 'default',
}
}
注意
- 因为 TypeScript 在检查 JSX 属性时只考虑了 props,你必须把有默认值的 props 标记为可选的
- 当使用
strictNullChecks
时,this.props.foo
的值可能会是undefined
。你可以使用非空断言(例如this.props.foo!
)或者类型守护(例如if (this.props.foo) {...}
)来移除undefined
。这是非常恼人的,因为实际上它是有默认值,所以绝对不会是undefined
,但是 TS 并不理解这个逻辑。这也是 TS 3.0 专门支持defaultProps
的主要原因之一。
函数组件的 defaultProps
您也可以在函数组件上使用 defaultProps
:
import React from 'react'
import { Text } from 'react-native'
interface Props {
foo: string;
bar: number;
}
const MyComponent: React.SFC<Props> = props => (
<Text>
Hello, {props.foo}, {props.bar}
</Text>
)
MyComponent.defaultProps = {
foo: 'default',
}
export default MyComponent
注意:你不必再使用
Partial<Props>
,因为 React.SFC 已经在 TS 2.1+ 被指定为 partial.
另一个可选的方案是解构你的 props 参数然后直接符默认值:
import React from 'react'
import { Text } from 'react-native'
interface Props {
foo: string;
bar: number;
}
const MyComponent: React.SFC<Props> = ({ foo = 'default', bar }) => {
return (
<Text>
Hello, {foo}, {bar}
</Text>
)
}