我正在尝试制作一个 React 组件,它允许用户将窗口滚动到屏幕顶部。我已经设置了组件和类型,但是我在设置窗口的属性时遇到了问题。我目前的错误是这样的:
<块引用>元素隐式具有“any”类型,因为索引表达式不是“number”类型。
如何正确处理窗口?
import { throttle } from 'lodash'
import React, { useState } from 'react'
import { useEventListener } from '../../hooks'
import { Arrow } from './styles'
interface ScrollRest {
showBelow: number,
className: string,
size: string
}
interface ScrollProps {
direction: string,
by: number,
to: number,
rest: ScrollRest
}
interface ScrollFunctionProps {
mode: string,
to: number
}
export default function Scroll( { direction = `up`, by, to, rest }: ScrollProps ) {
const { showBelow, className, size = `calc(0.6em + 30px)` } = rest
if ( ![`up`, `down`].includes( direction ) )
throw TypeError(
`Scroll component's direction prop must be either 'up' or 'down'`
)
if ( to && ( typeof to !== `number` || to <= 0 ) )
throw TypeError( `Scroll component's to prop must be a positive number` )
if ( by && typeof by !== `number` )
throw TypeError( `Scroll component's by prop must be a number` )
const [show, setShow] = useState( showBelow ? false : true )
const scroll = ( { mode, to }: ScrollFunctionProps ) =>
window[`scroll` + mode]( { top: to, behavior: `smooth` } ) // <- Error here!
const handleScroll = throttle( () => {
if ( !showBelow ) return
if ( window.scrollY > showBelow ) {
if ( !show ) setShow( true )
} else {
if ( show ) setShow( false )
}
}, 300 )
useEventListener( `scroll`, handleScroll )
const handleClick = () => {
if ( to ) scroll( { mode: `To`, to: to * window.innerHeight } )
else if ( by ) scroll( { mode: `By`, to: by * window.innerHeight } )
else if ( direction === `up` ) scroll( { mode: `To`, to: 0 } )
else scroll( { mode: `To`, to: document.body.scrollHeight } )
}
const arrowProps = { show, direction, className, size }
return <Arrow onClick={handleClick} {...arrowProps} />
}
答案 0 :(得分:1)
最简单的更改是将 mode
类型限制为 'scrollTo' | 'scrollBy'
方法名称:
interface ScrollFunctionProps {
mode: 'scrollTo' | 'scrollBy',
to: number
}
这允许 TypeScript 正确推断 window.scrollXXX(...)
方法调用的类型签名。
import { throttle } from 'lodash'
import React, { useState } from 'react'
import { useEventListener } from '../../hooks'
import { Arrow } from './styles'
interface ScrollRest {
showBelow: number,
className: string,
size: string
}
interface ScrollProps {
direction: string,
by: number,
to: number,
rest: ScrollRest
}
interface ScrollFunctionProps {
mode: 'scrollTo' | 'scrollBy', // restrict `mode` to known Window scroll method names
to: number
}
export default function Scroll( { direction = `up`, by, to, rest }: ScrollProps ) {
const { showBelow, className, size = `calc(0.6em + 30px)` } = rest
if ( ![`up`, `down`].includes( direction ) )
throw TypeError(
`Scroll component's direction prop must be either 'up' or 'down'`
)
if ( to && ( typeof to !== `number` || to <= 0 ) )
throw TypeError( `Scroll component's to prop must be a positive number` )
if ( by && typeof by !== `number` )
throw TypeError( `Scroll component's by prop must be a number` )
const [show, setShow] = useState( showBelow ? false : true )
const scroll = ( { mode, to }: ScrollFunctionProps ) =>
window[mode]( { top: to, behavior: `smooth` } )
const handleScroll = throttle( () => {
if ( !showBelow ) return
if ( window.scrollY > showBelow ) {
if ( !show ) setShow( true )
} else {
if ( show ) setShow( false )
}
}, 300 )
useEventListener( `scroll`, handleScroll )
const handleClick = () => {
if ( to ) scroll( { mode: `scrollTo`, to: to * window.innerHeight } )
else if ( by ) scroll( { mode: `scrollBy`, to: by * window.innerHeight } )
else if ( direction === `up` ) scroll( { mode: `scrollTo`, to: 0 } )
else scroll( { mode: `scrollTo`, to: document.body.scrollHeight } )
}
const arrowProps = { show, direction, className, size }
return <Arrow onClick={handleClick} {...arrowProps} />
}