Typescript 忽略 setState 函数返回类型的额外属性

问题描述 投票:0回答:2

我在这里束手无策。为什么 typescript 允许我在

setFormValidation
调用中返回任何内容,只要我在返回对象中提供 prevState spread 即可?它忽略了我在对象中返回的所有其他属性,即使
ValidationPayload
是我的映射类型上唯一允许的类型。
test: 6
不在
ValidationPayload
.

我在输入

useState
时做错了什么吗?这超出了打字稿的能力吗?即使我转换返回类型
as FormValidationState<T>
它仍然会忽略它。谢谢。


export interface ValidationPayload {
  isInvalid: boolean;
  error: string[];
}

export type FormValidationState<T extends string> = {
  [key in T | 'form']: ValidationPayload;
}

export function useFormValidation<T extends string>(keys: T[]) {

  function initFormValidation(keys: T[]): FormValidationState<T> {
    const initState = {} as FormValidationState<T>;
    keys.forEach((key: T) => {
      initState[key] = {
        isInvalid: false,
        error: [], // type checking here works
      };
    });

    initState.form = { isInvalid: false, error: [] };
    return initState;
  }

  const [formValidation, setFormValidation] = useState<FormValidationState<T>>(
    () => initFormValidation(keys),
  );

  setFormValidation((prevState: FormValidationState<T>) => {
    return {
      ...prevState,
      test: 6 // this should throw a ts error
    }
  })
}

reactjs typescript setstate typechecking
2个回答
0
投票

我认为这里的简短答案是

setFormValidation
调用类型为“(prevState: FormValidationState) => any”。最简单的检查方法是将鼠标悬停在函数上并亲自查看返回类型。

建议重构:

export interface ValidationPayload {
  isInvalid: boolean;
  error: string[];
}

export type FormValidationState = Record<string, ValidationPayload>

export function useFormValidation(keys: string[]): FormValidationState {
  const [formValidation, setFormValidation] = 
useState<FormValidationState>(initFormValidation(keys)); //Hooks always at the top of function body
  

  setFormValidation((prevState) => (
    {
      ...prevState,
      //...code
    }
  ))
}

在当前版本中,该片段可以在文件中的任何位置:

function initFormValidation(keys: string[]): FormValidationState {
    const initState: FormValidationState = {}
    keys.forEach((key) => {
      initState[key] = {
        isInvalid: false,
        error: [],
      };
    });

    initState.form = { isInvalid: false, error: [] }; //Not recommended
    //better to test overall form state elsewhere to avoid data overlap

    return initState;
  }

我只是把它放在常量文件夹或文件底部。


0
投票

我要求 ChatGPT 重构我的代码以提供更好的帮助:

export interface ValidationPayload {
  isInvalid: boolean;
  error: string[];
}

// Use Record type to define a generic FormValidationState type
export type FormValidationState<T extends string> = Record<T | 'form', ValidationPayload>;

export function useFormValidation<T extends string>(keys: T[]): FormValidationState<T> {
  const initFormValidation = () => {
    const initState: FormValidationState<T> = {} as FormValidationState<T>;
    keys.forEach((key: T) => {
      initState[key] = {
        isInvalid: false,
        error: [],
      };
    });

    initState.form = {
      isInvalid: false,
      error: [],
    };

    return initState;
  };

  // Initialize state using the initFormValidation function
  const [formValidation, setFormValidation] = useState<FormValidationState<T>>(
    initFormValidation(),
  );

  setFormValidation((prevState) => {
    // Use "as const" to ensure that the "test" key is treated as a literal type, not a string
    // This will throw a type error as expected
    return {
      ...prevState,
      test: {
        isInvalid: false,
        error: [],
      },
    } as const;
  });

  // Return the state object
  return formValidation;
}

© www.soinside.com 2019 - 2024. All rights reserved.