Search code examples
typescripttypescript-typingsreact-typescript

TypeScript runtime type-checks not working?


so I have a bit of an odd situation: I am attempting to validate a login request for a React web app using TypeScript, and am attempting to assign the type checking logic to a boolean. Upon doing so however, I'm getting an error of:

Argument of type 'FamilyInfo | undefined' is not assignable to parameter of type 'FamilyInfo'.
  Type 'undefined' is not assignable to type 'FamilyInfo'.

Here is the code in question:

      makeAPIRequest(loginRequest, (successful: boolean, serverResult: APIResult | undefined) => {
        const loginSuccess = (successful && (serverResult !== undefined) && (serverResult.familyInfo !== undefined));
        setBadLogin(!loginSuccess);
        if (loginSuccess) {
          // The line below fails 
          props.onSuccess(loginRequest, serverResult.familyInfo);
        }
      });

Here are what the relevant types look like:

interface APIResult {
  success: boolean;
  familyInfo: FamilyInfo | undefined;
}

interface LoginPanelProps {
  onSuccess: (loginInfo: LoginRequest, familyInfo: FamilyInfo) => void;
}

If I do the following, then everything works fine:

        if ((successful && (serverResult !== undefined) && (serverResult.familyInfo !== undefined))) {
          props.onSuccess(loginRequest, serverResult.familyInfo);
        }

But of course that's a bit redundant, so I'd like to keep it cleaner, and understand why type validation is failing here.

Edit: As a quick example, you can see this failing in TypeScript version v4.6.2 at https://www.typescriptlang.org/play?#code/ATCWDsBcFMCcDMCGBjawYGdLAN4CgRDgA3RAGwEYAuYLWCAc2AB9gBXcAE2ngmk4DcBYAF88w+B2SRQAe3DpoWCgAoIABzaQadRgEpcwosnkZZZaADoyshmvCbIeoSDEhJ4aXIWZIAJntHGl8DfCIQE3AsYGREcAB1WVgAa2AAXmBArWAAQjSMjm5ecH5gADIysActS1JKXPz2Lh4+TmcjQlB4TNiEpOTQjvDFZSzIWvIKduG3USA


Solution

  • Looks like this is by design with TypeScript: https://github.com/microsoft/TypeScript/issues/48241

    The solution looks something like this:

          makeAPIRequest(loginRequest, (successful: boolean, serverResult: APIResult | undefined) => {
            // Need to create a const of the familyInfo to be able to nicely check it.
            const familyInfo = serverResult?.familyInfo;
            const loginSuccess = (successful && (serverResult !== undefined) && serverResult.success && (familyInfo !== undefined));
            setBadLogin(!loginSuccess);
            if (loginSuccess) {
              props.onSuccess(loginRequest, familyInfo);
            }
          });