我在这里束手无策。为什么 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
}
})
}
我认为这里的简短答案是
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;
}
我只是把它放在常量文件夹或文件底部。
我要求 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;
}