Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
156 views
in Technique[技术] by (71.8m points)

How to avoid the double non-nullable check in TypeScript discriminated unions?

In below code TypeScript does not believe that if customMessage is undefined, className is NOT undefined:

export default class ClassRequiredInitializationHasNotBeenExecutedError extends Error {

  public static readonly NAME: string = "ClassRequiredInitializationHasNotBeenExecutedError";

  public constructor(
      parametersObject: {
        customMessage: string;
        className?: undefined;
      } | {
        className: string;
        customMessage?: undefined;
      }
  ) {

    super();

    this.name = ClassRequiredInitializationHasNotBeenExecutedError.NAME;

    if (typeof parametersObject.customMessage !== "undefined") {
      this.message = parametersObject.customMessage;
    } else {
      this.message = ClassRequiredInitializationHasNotBeenExecutedError.buildMessage({
          className: parametersObject.className
      })
    }
  }

  private static buildMessage(parametersObject: { className: string }): string {
    return `The class '${parametersObject.className}' has not been executed;`
  }
}

?? Fiddle

Error:

Type 'string | undefined' is not assignable to type 'string'.
  Type 'undefined' is not assignable to type 'string'.(2322)

I know that if will make the double check like:

if (typeof parametersObject.customMessage !== "undefined") {
    this.message = parametersObject.customMessage;
} else if (typeof parametersObject.className !== "undefined") {
    this.message = ClassRequiredInitializationHasNotBeenExecutedError.buildMessage({
        className: parametersObject.className
})

above example will work, but:

  1. I want to avoid else if (typeof parametersObject.className !== "undefined") if possible
  2. Event left it, TypeScript will not believe that one of customMessage or className has been initlized. Here is the example when it's critical:
let message: string;

if (typeof parametersObject.customMessage !== "undefined") {
    message = parametersObject.customMessage;
} else if (typeof parametersObject.className !== "undefined") {
    message = ClassRequiredInitializationHasNotBeenExecutedError.buildMessage({
        className: parametersObject.className
    })
}

console.log(message.length)
Variable 'message' is used before being assigned.(2454)

Please note that this question is about how to make TypeScript believe that if customMessage is undefined, className is NOT undefined and vice versa, not how to initialize this.message (the ClassRequiredInitializationHasNotBeenExecutedError class is just for example)

question from:https://stackoverflow.com/questions/65855805/how-to-avoid-the-double-non-nullable-check-in-typescript-discriminated-unions

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
 parametersObject: {
        customMessage: string;
        className?: undefined;
      } | {
        className: string;
        customMessage?: undefined;
      }

could be simplified to:

parametersObject: {
        customMessage: string;
      } | {
        className: string;
      }

as property?: undefined brings pretty no additional information.

Then the condition could be expressed as:

if ('customMessage' in parametersObject) {
  this.message = parametersObject.customMessage;
} else {
  this.message = ClassRequiredInitializationHasNotBeenExecutedError.buildMessage({
      className: parametersObject.className
  })
}

PLAYGROUND


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...