TypeScript报错:settings为何被推断为number | MutableRefObject类型?
为什么TypeScript会将settings推断为
number | MutableRefObject类型? 我遇到如下TypeScript错误:
Property 'current' does not exist on type 'number | MutableRefObject'
该错误出现在settings ref上。我从未将settings设为number类型,也未指定该类型,不理解为何TypeScript会推断它可能是number,它应该仅为ref类型。相关代码如下:
const useDatGui = (controls) => { const [updates, setUpdates] = useState(0) const loaded = useRef(false) const settings = useRef({ mode: 'scale', roomWidth: defaultRoom.width, roomDepth: defaultRoom.depth, roomHeight: defaultRoom.height, boxWidth: 0.4, boxDepth: 0.3, boxHeight: 0.2, }) useEffect(() => { if (typeof window != 'undefined' && !loaded.current) { const gui = new GUI() controls.forEach(([setting, { type, options }]) => { gui.add(settings.current, setting, options).onChange(() => { console.log('changed', setting) setUpdates(upd => (upd + 1) % 2) }) }) loaded.current = true return () => { gui.destroy() loaded.current = false } } }, []) return [updates, settings] } export default function Page() { const { selected, setState } = useContext(MyContext); const [updates, settings] = useDatGui([ ["mode", { type: "select", options: ["scale", "rotate", "translate"] }], ["roomHeight", { type: "range", options: 1 }], ["roomWidth", { type: "range", options: 1 }], ["roomDepth", { type: "range", options: 1 }], ["boxDepth", { type: "range", options: 0.1 }], ["boxWidth", { type: "range", options: 0.1 }], ["boxHeight", { type: "range", options: 0.1 }] ]) const wall = useMemo(() => { if (settings.current) { return ({ ...defaultRoom, height: settings.current.roomHeight, width: settings.current.roomWidth, depth: settings.current.roomDepth, }) } }, [defaultRoom, settings]) const box = { width: settings.current.boxWidth, depth: settings.current.boxDepth, height: settings.current.boxHeight } //... return ...
错误原因
问题出在useDatGui的返回值类型推断逻辑上:
- TypeScript默认会把函数返回的数组推断为元素类型是联合类型的数组,而非固定顺序的元组。
- 你的
useDatGui返回[updates, settings],其中updates是number类型,settings是MutableRefObject类型。TypeScript会将这个返回值推断为(number | MutableRefObject<...>)[],而非严格的[number, MutableRefObject<...>]。 - 当你在Page组件中解构这个返回值时,TypeScript会认为
updates和settings都可能是number或MutableRefObject类型,因此会抛出settings可能是number的错误。
解决方法
有两种简单的方式修复这个类型推断问题:
- 用
as const断言返回值类型
在useDatGui的return语句中添加断言,让TypeScript将返回值识别为只读元组:
return [updates, settings] as const;
- 显式指定函数返回值的元组类型
给useDatGui函数添加明确的返回类型定义,同时也可以给controls参数补充类型,让代码更严谨:
// 先定义settings的类型 type Settings = { mode: string; roomWidth: number; roomDepth: number; roomHeight: number; boxWidth: number; boxDepth: number; boxHeight: number; }; // 定义controls的类型 type ControlItem = [string, { type: string; options: string[] | number }]; const useDatGui = (controls: ControlItem[]): [number, React.MutableRefObject<Settings>] => { // 原函数内容不变 };
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

