文章目录
前言
自从GPT出现后,这篇文章就显得没啥作用了,这也是这这篇文章不更新的原因。以后我就记录一些使用心得和注意事项了。
心得
用import type去引入类型定义
例如:
import type { MyThing } from "./some-module.ts";
import也可以导入,和import type有什么区别呢?可以详看这篇文章:import 和 import type的区别
我这里也补充一个原因,在一些第三方库中,他们的package.json中有个types字段,值为这个库的tpye定义文件总入口,也就是说当我们用了import type去引入类型的时候,会根据package.json中types指定的文件去找对应的类型。
类型定义文件用.d.ts去命名
例如utils.d.ts
,我看第三方库和网上其他人都这么写,不过也有写.ts
的。
.ts
文件:可以编译成.js文件的,可以写类型代码又可以执行代码- .
d.ts
文件:只能写类型代码,不会生成.js文件,也不能写可以执行的代码,只能提供类型。
第三方库标签的函数默认参数类型定义用它自带的
但又有些第三方库的标签不能用react内置的,只能从库里去引入,例如@dnd-kit/core
:
import {
DndContext,
DragEndEvent,
} from '@dnd-kit/core'
function handleDragEnd(event: DragEndEvent) {
// ...
}
return (
<DndContext onDragEnd={handleDragEnd}>
<SortableContext>
{children}
</SortableContext>
</DndContext>
)
但大多数时候,你是不知道具体的类型要引入那个,此时可以通过编辑器的提示去对应引入,例如handleDragEnd中的event会提示,需要DragEndEvent类型,这时你再去引入即可。
枚举用普通的写法即可
别写一些花里胡哨的写法,就正经写最普通的写法即可,编译出来就编译出来,几十个枚举没多少代码量的:
enum SLIDE_ENV{
APPLE = 'A',
FISH = 'F'
}
也不要写常数枚举,运行时打印不出来的。
接口返参怎么处理
可以详细看我这篇文章【场景方案】如何去设计并二次封装一个好用的axios,给你提供一个另类写法,另加一些思考
类型定义
FC定义组件类型
这个是React中的一种函数组件类型,一般我们写函数组件的时候使用它来定义类型:
import React, { FC } from 'react'
const Home: FC = () => {
return (
<div></div>
)
}
export default Home
stlye类型定义
const style = useMemo(
() =>
({
...baseStyle,
} as React.CSSProperties),
[]
);
useState用泛型定义类型即可
const [selectedIds, setSelectedIds] = useState<string[]>([])
const [user, setUser] = useState<User | null>(null) // 给一个泛型,设定初值和后值
useRef类型定义的注意事项
// div
const containerRef = useRef<HTMLDivElement>(null)
// 一些第三方库组件可以这样
const scrollbarRef = useRef<InstanceType<typeof Scrollbars>>(null);
props推荐使用Partial
因为咱们组件定义的props属性并不是每一个参数都一定会传入的,所以使用Partial刚刚好:
type PropsType = {
isStar: boolean
setSelectedComponentId: (id: string) => void // 函数
children: JSX.Element | JSX.Element[] // 传入的是JSX
items: Array<{ id: string; [key: string]: any }> // 数组
}
const Header: FC = (props: Partial<PropsType> = {}) => {
// ...
}
写普通函数也可以这样:
function fn(opt: Partial<PropsType> = {}){
// ...
}
但如果想要严格限制就不用Partial:
type PropsType = {
isStar: boolean
isDeleted: boolean
}
const Header: FC = (props: PropsType) => {
// ...
}
// 或者
const Header: FC<PropsType> = props => {
// ...
}
// 或者
const Header: FC<PropsType> = (props: PropsType) => {
// ...
}
内置标签的函数默认参数类型定义用react内置的
例如input标签等,会有个onChange事件,默认参数可以用ChangeEvent
这样定义:
import React, { FC, useState, ChangeEvent } from 'react'
function handleChange(event: ChangeEvent<HTMLInputElement>) {
// ...
}
<input
onChange={handleChange}
/>
其实有些第三方库的事件也可以用react内置的,例如antd的Input标签也是可以用的。
其他例子:
const YourComponent: React.FC = () => {
const handleWheel = (e: WheelEvent<HTMLDivElement>) => {
// 这里写你的滚动事件处理逻辑
};
return <div onWheel={handleWheel}>滚动我!</div>;
};
把变量显示在页面上
一般情况下对象类型的变量无法通过JSX显示到页面上,我们可以用一个简单的函数实现转换:
export function str(o: unknown): React.ReactNode {
return typeof o === "object"
? JSON.stringify(o, null, 2)
: (o as React.ReactNode);
}
然后在JSX中就可以使用了:
<td>
{str(value)}
</td>
合并TailwindCss的类名
在使用TailwindCss时,有时候我们需要在类名中用一些JS表达式去条件选择类名,那么我们可以封装一个公共函数:
import clsx from "clsx";
import { ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
使用:
className={cn(
props.currentChat === null
? "bg-gray-50 text-indigo-600"
: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50",
"group flex gap-x-3 rounded-md -mx-2 p-2 text-sm leading-6 font-semibold cursor-pointer"
)}
上传文件类型定义
const [files, setFiles] = useState<File[]>([]);
把setState传入props
拿上面的setFiles传入来举例:
setFiles: React.Dispatch<React.SetStateAction<File[]>>;