-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Prerequisites
- I have searched the existing issues
- I understand that providing a SSCCE example is tremendously useful to the maintainers.
- I have read the documentation
- Ideally, I'm providing a sample JSFiddle, Codesandbox.io or preferably a shared playground link demonstrating the issue.
What theme are you using?
core
Version
5.24.7
Current Behavior
Right now, I have the following useState
:
const [extraErrors, setExtraErrors] = useState<ErrorSchema<IUserDataBoxConfigCreateInput> | undefined>(undefined);
where IUserDataBoxConfigCreateInput
is:
interface IUserDataBoxConfigCreateInput {
storageId: string;
name: string;
description?: string;
}
and I try to set the new state with the following function, to preserve any existing errors:
setExtraErrors((prevExtraErrors: ErrorSchema<IUserDataBoxConfigCreateInput> | undefined): ErrorSchema<IUserDataBoxConfigCreateInput> | undefined => {
const NEW_ERROR = "Could not get username availability.";
if (prevExtraErrors === undefined) {
return {
name: {
__errors: [NEW_ERROR]
} satisfies FieldErrors
} satisfies ErrorSchema<IUserDataBoxConfigCreateInput>;
}
return {
...prevExtraErrors,
name: {
__errors: prevExtraErrors.name?.__errors === undefined ? [NEW_ERROR] : [...prevExtraErrors.name.__errors, NEW_ERROR]
} satisfies FieldErrors
} satisfies ErrorSchema<IUserDataBoxConfigCreateInput>;
});
Unfortunately, this yields a type error:
Type '{ __errors: string[]; }' is not assignable to type 'ErrorSchema<string>'.
Type '{ __errors: string[]; }' is not assignable to type 'string'.ts(2322)
UserDataBoxConfigCreateInput.ts(8, 3): The expected type comes from property 'name' which is declared here on type 'ErrorSchema<IUserDataBoxConfigCreateInput>'
(property) name?: ErrorSchema<string> | undefined
After playing with the types and getting angry after not managing to fix it, I asked ChatGPT what's wrong with my code, also providing it with the ErrorSchema
type definition from RJSF for context. And so, a surprising response was given:
"
When T = string
, then ErrorSchema<string>
resolves to:
FieldErrors & {
[key in keyof string]?: ErrorSchema<T[key]>
}
But keyof string
is not never
!, it is actually string
, number
, Symbol
, etc., because in TypeScript:
keyof string === keyof String === "length" | "toUpperCase" | ...
So ErrorSchema<string>
ends up not just being FieldErrors
, but some monster like:
{
__errors?: string[];
length?: ErrorSchema<...>;
toUpperCase?: ErrorSchema<...>;
...
}
And then your code:
name: { __errors: [NEW_ERROR] } satisfies FieldErrors
Is not assignable to this complex monster structure.
"
While I am not exactly sure if this is the case or not, it also provided a solution:
"
Update ErrorSchema
to only recurse on objects, like this:
export type ErrorSchema<T = any> =
FieldErrors & (T extends object ? {
[key in keyof T]?: ErrorSchema<T[key]>;
} : {});
This says: "If T
is an object
(like a form field with properties), recurse. Otherwise, stop at FieldErrors
."
This will now allow things like:
const errs: ErrorSchema<{ name: string }> = {
name: {
__errors: ["Nope"]
}
};
And disallow ErrorSchema<string>
from expecting keys like length
, charAt
, etc.
"
Sure enough, making the change to ErrorSchema
locally fixed my error.
Expected Behavior
I expect no type error.
Steps To Reproduce
No response
Environment
Anything else?
This is the first time an LLM has fixed a library issue for me. I am impressed.