Reactjs 打字脚本可以';不要告诉我';如果参数未定义,m将提前返回

Reactjs 打字脚本可以';不要告诉我';如果参数未定义,m将提前返回,reactjs,typescript,react-hooks,Reactjs,Typescript,React Hooks,我将TypeScript与React一起使用,我不明白为什么TS不能判断如果previous是undefined,那么下面的钩子会提前返回。它抱怨previous.length(“对象可能未定义”),因为它认为previous可能是undefined,但情况并非如此,因为如果是这样,函数将提前返回 function ReactComponent() { const previous = usePrevious(value) React.useEffect(() =&

我将TypeScript与React一起使用,我不明白为什么TS不能判断如果
previous
undefined
,那么下面的钩子会提前返回。它抱怨
previous.length
(“对象可能未定义”),因为它认为previous可能是
undefined
,但情况并非如此,因为如果是这样,函数将提前返回

  function ReactComponent() {
      const previous = usePrevious(value)

      React.useEffect(() => {
        if (previous === undefined) {
           return
        }

        if (previous.length) { // TS says "Object is possibly undefined" despite the return gate above
   
        }
    
      }, [previous])

      return null
  }
奇怪的是,这只是React钩子中的一个问题。下面的代码不抱怨

const bar: Array<number> | undefined = undefined

function foo() {
  if (bar === undefined) {
    return
  }

  if (bar.length) { // TS does NOT complain here
    
  }
}
我可以通过明确说明此函数的返回类型为
any
来解决此问题。换句话说,通过将
函数usePrevious(value:any){…}
更改为
函数usePrevious(value:any):any{…}


为什么要修复它对我来说仍然是一个谜,所以我现在就把它打开。

usePrevious
有一个始终
未定义的返回类型。尝试将其键入为:

function usePrevious<T>(value: T): T | undefined {
  const ref = React.useRef<T>();
  
  React.useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}
函数usePrevious(值:T):T |未定义{
const ref=React.useRef();
React.useffect(()=>{
参考电流=值;
},[价值];
返回参考电流;
}

usePrevious
具有始终
未定义的返回类型。尝试将其键入为:

function usePrevious<T>(value: T): T | undefined {
  const ref = React.useRef<T>();
  
  React.useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}
函数usePrevious(值:T):T |未定义{
const ref=React.useRef();
React.useffect(()=>{
参考电流=值;
},[价值];
返回参考电流;
}

该死,这和我刚才写的@Federkun lol很相似

import { useRef, useEffect, MutableRefObject } from 'react';
type CustomNonNullable<T> = T extends null | undefined
    ? never
    : T;
// if generic parameter <T> is a function Type, it extracts the return type
type ReturnTypeOf<T extends (...args: any) => any> = T extends (
    ...args: any
) => infer U
    ? U
    : any;
export default function usePrevious<T, P>(
    value: T,
    previousValue: P
) {
    const refMutable: MutableRefObject<T | undefined> = useRef<T>(); // refMutable: MutableRefObject<T | undefined>
    const refPrevious: MutableRefObject<P | undefined> = useRef<P>(); // refInitial: RefObject<T>
    // use nonullable ! operator to override refMutable.current conditionally undefined
    const NonnullableValue: CustomNonNullable<T> = refMutable!.current! ?? value!;
    const NonnullablePreviousValue: CustomNonNullable<P> = refPrevious!.current! ?? previousValue!;
    useEffect(() => {
        refMutable.current = value ?? undefined;
        refPrevious.current = previousValue ?? undefined;
    }, [value, previousValue]);
    return { NonnullablePreviousValue, NonnullableValue };
}

let y: ReturnTypeOf<typeof usePrevious>;
/**
 * @var y inferred
    let y: {
    NonnullablePreviousValue: unknown;
    NonnullableValue: unknown;
}
 */

export const inferredYObject = () => {
    const { NonnullablePreviousValue, NonnullableValue } = y;
    const trulyPrivateObject = Object.freeze({
        NonnullablePreviousValue,
        NonnullableValue
    } as const);
    return trulyPrivateObject;
};

/**
 * @function inferredYObject has the following type
 *Readonly<{
    readonly NonnullablePreviousValue: unknown;
    readonly NonnullableValue: unknown;
}>
 * this makes it safe at runtime -- prevents XSSmodification
 */

从'react'导入{useRef,useffect,MutableRefObject};
类型CustomNonNullable=T扩展null |未定义
? 从未
:T;
//如果泛型参数是函数类型,它将提取返回类型
类型ReturnTypeOf any>=T扩展(
…阿格斯:有吗
)=>推断U
? U
:任何;
导出默认函数usePrevious(
值:T,
先前值:P
) {
常量refMutable:MutableRefObject=useRef();//refMutable:MutableRefObject
const refPrevious:MutableRefObject

=useRef

();//refInitial:RefObject //使用nonullable!运算符重写refMutable.current有条件未定义 常量NonnullableValue:CustomNonNullable=refMutable!。current!?value!; 常量NonnullablePreviousValue:CustomNonNullable

=refPrevious!.current!?previousValue!; useffect(()=>{ refMutable.current=值??未定义; refPrevious.current=previousValue??未定义; },[value,previousValue]); 返回{NonnullablePreviousValue,NonnullableValue}; } 让y:ReturnTypeOf; /** *@var y 让我来说说:{ NonnullablePreviousValue:未知; 非NullableValue:未知; } */ 导出常量推断对象=()=>{ 常量{NonnullablePreviousValue,NonnullableValue}=y; const trulyprovateobject=Object.freeze({ 不可为空的PreviousValue, 非空值 }作为常量); 返回真正私有的对象; }; /** *@function inferredYObject具有以下类型 *只读 *这使得它在运行时安全—防止XSM修改 */


该死,这和我刚才写的@Federkun lol很相似

import { useRef, useEffect, MutableRefObject } from 'react';
type CustomNonNullable<T> = T extends null | undefined
    ? never
    : T;
// if generic parameter <T> is a function Type, it extracts the return type
type ReturnTypeOf<T extends (...args: any) => any> = T extends (
    ...args: any
) => infer U
    ? U
    : any;
export default function usePrevious<T, P>(
    value: T,
    previousValue: P
) {
    const refMutable: MutableRefObject<T | undefined> = useRef<T>(); // refMutable: MutableRefObject<T | undefined>
    const refPrevious: MutableRefObject<P | undefined> = useRef<P>(); // refInitial: RefObject<T>
    // use nonullable ! operator to override refMutable.current conditionally undefined
    const NonnullableValue: CustomNonNullable<T> = refMutable!.current! ?? value!;
    const NonnullablePreviousValue: CustomNonNullable<P> = refPrevious!.current! ?? previousValue!;
    useEffect(() => {
        refMutable.current = value ?? undefined;
        refPrevious.current = previousValue ?? undefined;
    }, [value, previousValue]);
    return { NonnullablePreviousValue, NonnullableValue };
}

let y: ReturnTypeOf<typeof usePrevious>;
/**
 * @var y inferred
    let y: {
    NonnullablePreviousValue: unknown;
    NonnullableValue: unknown;
}
 */

export const inferredYObject = () => {
    const { NonnullablePreviousValue, NonnullableValue } = y;
    const trulyPrivateObject = Object.freeze({
        NonnullablePreviousValue,
        NonnullableValue
    } as const);
    return trulyPrivateObject;
};

/**
 * @function inferredYObject has the following type
 *Readonly<{
    readonly NonnullablePreviousValue: unknown;
    readonly NonnullableValue: unknown;
}>
 * this makes it safe at runtime -- prevents XSSmodification
 */

从'react'导入{useRef,useffect,MutableRefObject};
类型CustomNonNullable=T扩展null |未定义
? 从未
:T;
//如果泛型参数是函数类型,它将提取返回类型
类型ReturnTypeOf any>=T扩展(
…阿格斯:有吗
)=>推断U
? U
:任何;
导出默认函数usePrevious(
值:T,
先前值:P
) {
常量refMutable:MutableRefObject=useRef();//refMutable:MutableRefObject
const refPrevious:MutableRefObject

=useRef

();//refInitial:RefObject //使用nonullable!运算符重写refMutable.current有条件未定义 常量NonnullableValue:CustomNonNullable=refMutable!。current!?value!; 常量NonnullablePreviousValue:CustomNonNullable

=refPrevious!.current!?previousValue!; useffect(()=>{ refMutable.current=值??未定义; refPrevious.current=previousValue??未定义; },[value,previousValue]); 返回{NonnullablePreviousValue,NonnullableValue}; } 让y:ReturnTypeOf; /** *@var y 让我来说说:{ NonnullablePreviousValue:未知; 非NullableValue:未知; } */ 导出常量推断对象=()=>{ 常量{NonnullablePreviousValue,NonnullableValue}=y; const trulyprovateobject=Object.freeze({ 不可为空的PreviousValue, 非空值 }作为常量); 返回真正私有的对象; }; /** *@function inferredYObject具有以下类型 *只读 *这使得它在运行时安全—防止XSM修改 */


可选链接操作符是否修复它:
previous?.length
?虽然
previous?.length
抱怨“类型“never”上不存在属性“length”,但不确定它为什么在一种情况下抱怨,而在另一种情况下不抱怨。与
previous!相同!。长度
如何声明
在您的情况下,
usePrevious
的返回类型不总是未定义吗?可选的链接操作符是否修复了它:
previous?.length
?虽然
previous?.length
抱怨“类型“never”上不存在属性“length”,但不确定它为什么在一种情况下抱怨,而在另一种情况下不抱怨。与
previous!相同!。长度
如何声明
呢?在您的情况下,
useproval
的返回类型不总是未定义吗?谢谢,这很有效。我刚刚意识到我应该在所有地方使用像这样的泛型,谢谢,这很有效。我刚刚意识到我应该在所有地方使用这样的泛型