Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

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

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)


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

1 Reply

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...