Props
- 优先使用
interface 声明组件 Props,用户可以在需要的时候轻易的拓展 Props。当 interface
满足不了或需要限制用户扩展的情况下,使用 type 声明。
- 不要在 Function Component 中使用
React.FC<Props>,直接设置 (props: Props) => {}。
- 不使用
defaultProps,通过解构赋值实现默认值设置。
Hooks
- useState: 可以推导类型,但你仍可以声明类型
useState<Post>({})。
- useEffect: 本身接受的返回值为函数或
undefined,使用箭头函数简写时需注意是否返回了其他类型的返回值。
- useRef: 当使用于 HTML 元素时,无需处理 null 的情况,如
useRef<HTMLInputElement>(null)。当用于保存值时,需处理其他类型的情况,如
useRef<number | null>(null)
- 自定义 Hook: 当你参考
useState 实现的 useTheme 返回了 [theme, setTheme]
作为返回值时,类型系统会将返回值认为是包含了 string 和 Dispatch<SetStateAction<string>>
的数组,返回值的每一个子项都被认为可能是这两种类型之一,从而无法正确对应类型。你可以使用 const 断言返回值
[theme, setTheme] as const 或显示声明返回值类型
[theme, setTheme] as [string, Dispatch<SetStateAction<string>>]
来解决这个问题。建议返回值大于 2 个的自定义 Hooks 优先使用对象而不是数组。
Context
如果没有默认值,需显式指定为 null,如 createContext<User | null>(null)。
当类型可能为 null 时,可通过判断是否为 null 进行使用。或提供一个抽象的 useUser
并在方法中进行处理。或明确不会为 null : createContext<User>(null!)
const useUser = () => {
const currentUser = useContext(CurrentUserContext)
if (!currentUser) {
throw new Error('useUser has to be used within <CurrentUserContext.Provider>')
}
return currentUser
}
Event
-
内联写法可以自动推导出方法类型: onClick={e => {}}
-
如果单独声明了方法,需要显示的指定事件类型
const onChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({ text: e.currentTarget.value })
}
// or
const onChange: React.ChangeEventHandler<HTMLInputElement> = e => {
this.setState({ text: e.currentTarget.value })
}
-
如果不关心具体的事件类型,则可以直接指定为 SyntheticEvent
const onSubmit = (e: React.SyntheticEvent) => {
e.preventDefault()
}
Ref
createRef<HTMLButtonElement>()
forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {})
常见技巧
Union Types and Type Guarding
通过联合类型组合类型,通过类型守卫去推断不同的类型
interface Admin {
role: string
}
interface User {
email: string
}
// Method 1: use `in` keyword
function redirect(user: Admin | User) {
if ('role' in user) {
// use the `in` operator for typeguards since TS 2.7+
routeToAdminPage(user.role)
} else {
routeToHomePage(user.email)
}
}
function isAdmin(user: Admin | User): user is Admin {
return (user as any).role !== undefined
}
Type Assertion
使用 ! 断言非空 ,使用 as 断言类型。
Intersection Types
使用交叉类型组合复用类型
type BaseProps = {
className?: string
style?: React.CSSProperties
name: string // used in both
}
type DogProps = { tailsCount: number }
type HumanProps = { handsCount: number }
export const Human = (props: BaseProps & HumanProps) => {}
export const Dog = (props: BaseProps & DogProps) => {}
Inferred Types
通过 typeof 获取类型
const [state, setState] = useState({
foo: 1,
bar: 2,
})
const someMethod = (obj: typeof state) => {
}
export function App = (props: Props) => {}
type P = React.ComponentProps<typeof App> // get Props
通过 ReturnType 获取返回类型,通过 Parameters 获取参数类型。
处理不存在的类型
使用 declare module 'MODULE_MANE' 来拓展第三方依赖中不满足使用的类型。
declare module '*.png'
import * as logo from './logo.png'
tsconfig
相对于常规 TypeScript 在 React 项目中你可能需要显示配置下列配置
{
"compilerOptions": {
"esModuleInterop": true,
"jsx": "react-jsx",
"typeRoots": ["./typings", "./node_modules/@types"]
}
}
Reference