在react项目里,遇到的ts语法:
1.
type Props={
value: string[],
onChange:(tags:string[])=>void
}
const TagSection : React.FC <Props> =(props)=>{
const [tags,setTags]=useState<string[]>(['衣服','餐饮','住房','交通'])
}
定义一个函数组件TagSection,要指明它的类型:React.FC(Function Component)。
接受一个props外部属性的参数,如果这个props里不只有children,还有父组件给它传的一些变量,函数之类的,那就要声明这个props的类型。props也可以接受函数。声明函数的类型时,先写函数名,:,箭头函数的形式。括号里写参数的类型,没有参数就空着。没有返回值就写void。
参数props的类型用尖括号。<Props>
使用useState初始化一个数据,如果类型复杂,比如是一个字符串数组,也要指明类型。类型写在<>里
2. 可以声明联合类型,缩小类型范围。
type Category='-' | '+'
function Money() {
const [selectedRecord,setSelectedRecord]=useState({
category:'-' as Category,
tags:[] as string[],
note:'',
amount:'0'
})
category是字符串类型,但是它只有'-' 或 '+'两种情况,所以可以缩小它的类型范围。用type Category='-' | '+'声明一个联合类型,表示category只有这两种情况,如果你写了其他字符串,就会报错。
3.
背景需要:一个输入框组件,包含一个label,label里边有一个文本和input。这个输入框我们在多个地方需要,并且样式一样。所以我们把这个封装成一个Input组件。
//Input.tsx
type Props={
label: string,
placeholder: string,
value: string,
onChange: (e: any)=>void
}
const Input: React.FC <Props> =(props)=>{
return (
<Label>
<span>{props.label}</span>
<input type='text' placeholder={props.placeholder}
value={props.value} onChange={props.onChange}/>
</Label>
)
}
export default Input
因为使用它的不同地方,文本,placeholder等都是不同的,所以这些属性需要做成props等待父组件传进去。
定义一个Props类型。
在场景一使用:
const NoteSection: React.FC <Props> =(props)=>{
const note=props.value
const onChange=(e: any)=>{
props.onChange(e.target.value)
}
return (
<NoteWrapper>
<Input label='备注:' placeholder='在这里写备注~'
value={note} onChange={onChange}>
</Input>
</NoteWrapper>
)
}
export default NoteSection
在Input组件里传props。
可是在Input组件里这样接受props使代码很繁琐
3.1 改进:
既然我们传的props都是原本的input标签上的属性,如placeholder ,value ,onChange等。那我们可以在定义Props类型时,不一一展开写都有哪些属性,而是直接继承input标签的所有属性。
type Props={
label: string,
}& React.InputHTMLAttributes<HTMLInputElement>
这么写的意思就是,props除了有个label属性外,还继承input元素的所有属性。input标签有哪些属性,props里也同样有。就代表现在已经存在了props.label,props.palceholder等
在使用这些属性的时候,能不能再简写?不然有一百个属性,就要在input标签里写一百次。使用...rest语法
type Props={
label: string,
}& React.InputHTMLAttributes<HTMLInputElement>
const Input: React.FC <Props> =(props)=>{
const {label,children,...rest}=props // 1
return (
<Label>
<span>{label}</span>
<input {...rest}/> // 2
</Label>
)
}
export default Input
使用析构赋值,把props里边的所有属性命名成同名属性。props里除了label, children属性外,还有所有的input标签的属性,使用...rest语法,表示把props里剩余的其他属性展开拷贝过来。
使用的时候,直接在input标签里,用rest使用。外边的{}表示里边是JS代码,里边把rest对象展开
这样做的意义就是把props里的所有input标签自带的属性拷贝到真正的input标签上。避免了要把所有属性全部写一遍的做法。使代码看起来很简洁。这样写和上边原始的写法效果是等价的。
在某个父组件里使用Input组件时,还是照常传props,写法不变。
4. Omit
我想声明两个类型:
type RecordItem={
category: '-' | '+',
tagsId: number[],
note: string,
amount: string
}
type TimedRecord={
category: '-' | '+',
tagsId: number[],
note: string,
amount: string,
createdAt: string
}
第二个只比第一个多了一个属性。为了不重复,可以有两种方法:
4.1 & 连接
type RecordItem={
category: '-' | '+',
tagsId: number[],
note: string,
amount: string
}
type TimedRecord=RecordItem & {
createdAt: string
}
4.2 Omit 函数
type TimedRecord={
category: '-' | '+',
tagsId: number[],
note: string,
amount: string,
createdAt: string
}
type RecordItem=Omit<TimedRecord,'createAt'>
先定义多的那个类型。用TS提供的一个函数:Omit 我不要这个类型里的某一项。(忽略)
如果不要多个属性:type RecordItem=Omit<TimedRecord,'createAt' | 'amount'>