封装React组件增加TS类型校验

108 阅读2分钟
  1. 调用函数式组件要通过 ref 访问时,需要用 forwardRef 转发ref,暴露命令式句柄,将收到的 ref 传递给 useImperativeHandle 并指定你想要暴露给 ref 的值。 为暴露的方法增加TS类型,使用 forwardRef泛型,forwardRef<T, P>,T定义组件想要暴露出的属性和方法,P定义组件接受的属性和方法。 当在父组件调用时,用 useRef<T>creatRef<T> 获取ref实例。

    import React, { forwardRef, Ref, useImperativeHandle, useRef } from 'react';
    
    // 假设我们有一个输入框组件,它接受一个value prop和一个onChange回调 
    interface InputProps { 
        value: string; 
        onChange: (event: React.ChangeEvent<HTMLInputElement>) => void; 
    } 
    
    // 假设我们想要暴露一个focus方法来聚焦输入框 
    interface InputRef { 
        focus: () => void; 
    } 
    
    // 使用forwardRef和泛型来定义组件 
    
    const MyInput = forwardRef<InputRef, InputProps>((props, ref) => { 
        const inputRef = useRef<HTMLInputElement>(null); 
    
        useImperativeHandle(ref, () => ({
            focus: () => { 
                if (inputRef.current) { 
                    inputRef.current.focus(); 
                    } 
            }, 
        })); 
    
        return <input ref={inputRef} value={props.value} onChange={props.onChange} />; 
    }); 
    
    // 使用组件时,你可以使用React.createRef来获取ref的类型 
    const App = () => { 
        const inputRef = React.createRef<InputRef>(); 
    
        return ( 
            <div>
                <MyInput ref={inputRef} value="Hello" onChange={(e) => console.log(e.target.value)} /> 
                <button onClick={() => inputRef.current?.focus()}>Focus Input</button> 
            </div> 
        ); 
    }; 
    
    export default App;
    
  2. 获取元素Ref时,用 const xxRef = useRef<HTMLAnchorElement>(null) 定义,泛型中写入元素类型。

  3. Antd 定义的Form组件属性要继承于 FormComponentProps<any>,props 中获取的 form 属性 TS类型是 WrappedFormUtils

  4. JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): any,JSON.parse 接受的参数是字符串,不要传入 null 值。

  5. 当数组中包含两种对象类型时,可以通过联合类型(Union Type)定义

    // 定义两种对象类型
     interface Person {
         name: string;
         age: number;
         isHuman: true;
     }
    
     interface Animal {
         name: string;
         species: string;
         isHuman: false;
     }
    
     // 使用联合类型定义数组
     const mixedArray: (Person | Animal)[] = [
         { name: 'Alice', age: 30, isHuman: true },
         { name: 'Bobcat', species: 'Felis rufus', isHuman: false },
         // ... 其他元素
     ];
    
     // 当从数组中取出元素时,你需要使用类型守卫或类型断言来确保类型安全
     function printName(item: Person | Animal) {
         if (item.isHuman) {
             // 在这里,TypeScript知道item是Person类型
             console.log(`Person: ${item.name}`);
         } else {
             // 在这里,TypeScript知道item是Animal类型
             console.log(`Animal: ${item.name}`);
         }
     }
    
     // 遍历数组并打印名称
     mixedArray.forEach(printName);
    

总结

通过增加 TypeScript 类型,对组件功能完整梳理了一遍,清楚有哪些方法和属性在使用,哪些是无用的,当调用有 TS 类型的组件时,属性和方法对会有类型提示,如果传入的不符合类型定义,也会报TS错误,保证组件的正确使用,也能提高组件后续的可维护性。