There are two issues related to type safety when building Deaconn via next build
. While these errors can be safely ignored and the website will operate without any major issues because they only appear with stricter overrides to the compiler options, this solution isn't ideal because we shouldn't be using variables and objects of type any
anywhere with TypeScript. I will admit this is a bigger concern with another project of mine also utilizing the same frameworks used for Deaconn (Best Mods). The temporary solution involves commenting out the following configuration from the .eslintrc.cjs
file.
overrides: [
{
extends: [
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
files: ["*.ts", "*.tsx"],
parserOptions: {
project: "tsconfig.json"
}
}
]
Passing Formik Form As any
Type
The first issue relates to src/components/forms/main.tsx
.
import React from "react";
import { FormikProvider } from "formik";
const Main: React.FC<{
form: any,
children: React.ReactNode,
submitBtn: JSX.Element,
type?: string
}> = ({
form,
children,
submitBtn,
type="POST"
}) => {
return (
<FormikProvider value={form}>
<form method={type} onSubmit={form.handleSubmit}>
{children}
{submitBtn}
</form>
</FormikProvider>
);
}
export default Main;
Errors are as follows.
./src/components/forms/main.tsx
6:11 Warning: Unexpected any. Specify a different type. @typescript-eslint/no-explicit-any
17:32 Error: Unsafe assignment of an `any` value. @typescript-eslint/no-unsafe-assignment
18:43 Error: Unsafe assignment of an `any` value. @typescript-eslint/no-unsafe-assignment
18:43 Error: Unsafe member access .handleSubmit on an `any` value. @typescript-eslint/no-unsafe-member-access
We simply need to specify a valid type for the form
parameter. However, this is more complicated since this components acts as a wrapper for all of our forms meaning the form types are different each time (e.g. different initiated values).
Reparsing Objects & Variables Via JSON.parse()
When Passing As Prop
When passing a prop from Next's getServerSideProps()
async function, it requires being able to serialize the prop's values via JSON. For example, say we have the following code.
export async function getServerSideProps(ctx: GetServerSidePropsContext) {
let article: Article | null = null;
/* Retrieve article... */
return {
props: {
article: article
}
}
}
The Article
type includes a Date
object field (createdAt
) resulting in the above causing the following error.
Error: Error serializing `.article.createdAt` returned from `getServerSideProps` in "...".
Reason: `object` ("[object Date]") cannot be serialized as JSON. Please only return JSON serializable data types.
The solution I've always used was converting the object to a JSON string and then parsing the string as a JSON object. Typically, you'd use JavaScript's JSON.stringify()
and JSON.parse()
functions. However, JSON.parse()
returns any
which results in the following Next error when having the configuration mentioned at the beginning of the issue uncommented.
48:13 Error: Unsafe assignment of an `any` value. @typescript-eslint/no-unsafe-assignment
With that said, using JSON.parse()
results in the createdAt
field being set to a string
instead of a Date
object which is invalid type safety. There are a couple of things I've thought of doing before realizing this. I was initially trying to create a JSON validator that would validate JSON.parse()
against a passed type
and return the object as that specific type, but that was difficult (read below). However, as just stated, JSON.parse()
sets the Date
object to a string which renders the validator useless since we have another problem.
I believe I'm going to need to create new types for each object we pass via props that contains a string
field (e.g. createdAtStr
) that is set to the createdAt
field as a string from the Date
object. The components receiving the prop already parses the date as a string (e.g. const articleDate = new Date(article?.createdAtStr ?? Date.now())
), so this should be all we need to do.
Looking Into Validating JSON.parse()
(No Good)
I've read Stack Overflow threads (1, 2), but there isn't an easy solution without writing a lot of validation code alongside JSON.parse()
. This answer from Stack Overflow is the best I could find and even then it's complicated. There are other options I explored such as using ZOD validation. However, since there are a lot of times we use this method to pass props along with many different types, I wasn't able to find something that easily converts a typical TypeScript type to a ZOD schema without writing out a schema for each type which would be quite annoying in my opinion.
I'll need to research these issues further and once I have updates, I will reply to this issue.