typescript: enable --exactOptionalPropertyTypes

In Typescript when you say

  interface iface {
    prop?: string;
  }

it means that the `iface` type can have an optional property `prop`
present, and if it is present it must be a string *or* `undefined`.  The
reason for that is that given an instance `x` of type `iface`, if you
say `x.prop` then the result of that will be `undefined` if the property
is missing, so in some sense the ideas of "missing" and "`undefined`"
are semi-fungible.

This idea that a property can be present but defined to `undefined` is
incompatible with our definition of JsonObject, which doesn't permit
`undefined` to appear as a value in JSON documents, and has gotten us
into a lot of trouble in the past, trying to create types to describe
things that the bridge sends to us, in cases where a field may or may
not be present.

It seems like the Typescript people changed their mind about this.  In
4.4 they introduced the "recommended" `--exactOptionalPropertyTypes`
flag which doesn't implicitly add `undefined` as a permitted value as a
side-effect of using `?`.

  https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes
  https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html#exact-optional-property-types---exactoptionalpropertytypes

This hasn't been made part of `--strict` yet because of how disruptive
it would be.

Let's switch this option on for our code and fix a couple of places
where it causes problems.  One example is the `id` field of
`HelperTextItem`: it's optional, but if present, it must be a string.

Fix a bit of whitespace in tsconfig.json while we're at it.
This commit is contained in:
Allison Karlitskaya 2024-06-11 15:04:08 +02:00
parent 2ccaa6df36
commit 75b4087cbf
3 changed files with 6 additions and 5 deletions

View file

@ -32,7 +32,7 @@ import "context-menu.scss";
*/
export const ContextMenu = ({ parentId, children } : {
parentId: string,
children?: React.ReactNode[],
children?: React.ReactNode,
}) => {
const [visible, setVisible] = React.useState(false);
const [event, setEvent] = React.useState<MouseEvent | null>(null);

View file

@ -24,8 +24,8 @@ import { HelperText, HelperTextItem } from "@patternfly/react-core/dist/esm/comp
export const FormHelper = ({ helperText, helperTextInvalid, variant, icon, fieldId } :
{
helperText?: string | null,
helperTextInvalid?: string | null,
helperText?: string | null | undefined,
helperTextInvalid?: string | null | undefined,
variant?: "error" | "default" | "indeterminate" | "warning" | "success",
icon?: string,
fieldId?: string,
@ -40,7 +40,7 @@ export const FormHelper = ({ helperText, helperTextInvalid, variant, icon, field
<FormHelperText>
<HelperText>
<HelperTextItem
id={fieldId ? (fieldId + "-helper") : undefined}
{...fieldId && { id: fieldId + '-helper' }}
variant={formHelperVariant}
icon={icon}>
{formHelperVariant === "error" ? helperTextInvalid : helperText}

View file

@ -13,6 +13,7 @@
"checkJs": true,
"baseUrl": "./pkg/lib",
"esModuleInterop": true,
"exactOptionalPropertyTypes": true,
"jsx": "react",
"lib": [
"dom",
@ -20,7 +21,7 @@
],
"noEmit": true, // we only use `tsc` for type checking
"skipLibCheck": true, // don't check node_modules
"strict": true,
"strict": true,
},
"include": [
"pkg/**/*"