Home > Net >  Typing for: Either property "a" is set or property "b" and "c" is set
Typing for: Either property "a" is set or property "b" and "c" is set

Time:10-07

Is there a way for typescript to know that either this.a will be set or this.b and this.c will be set?

Taking the following code, there should never be an instance where all items will be set or none will be set due to how the constructor is setup.

export class MyClass {

  readonly a?: SomeClass
  readonly b?: string
  readonly c?: string

  constructor(a: SomeClass)
  constructor(b: string, c: string)
  constructor(...args: ([SomeClass] | [string, string])) {
    if(args.length === 1) {
      this.a = args[0]
    } else {
      this.b = args[0]
      this.c = args[1]
    }
  }

  echo() {
    if (this.a instanceof SomeClass) {
    } else {
       someFunction(this.b, this.c)
    }
  }

}

someFunction is giving the following error:

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

I know I could do an else if(typeof this.b === 'string' && typeof this.c === 'string'), but that seems like a long approach. Is there another way that this could be done?

Example

CodePudding user response:

Either property "a" is set or property "b" and "c" is set

The key concept here is "or". Use a TypeScript union type to achieve it i.e. {a} | {b,c}. Here is a complete example:

class SomeClass { };

export class MyClass {

    readonly values: { a: SomeClass } | { b: string, c: string }

    constructor(a: SomeClass)
    constructor(b: string, c: string)
    constructor(...args: ([SomeClass] | [string, string])) {
        if (args.length === 1) {
            this.values = { a: args[0] };
        } else {
            this.values = { b: args[0], c: args[1] };
        }
    }

    echo() {
        if ('a' in this.values) {
            const { a } = this.values;
        } else {
            const { b, c } = this.values;
        }
    }
}

CodePudding user response:

//you can ignore undefined
if (!this.a) {
    someFunction(this.b!, this.c!)    
}

// or better way: check if strings are assigned
if(this.b && this.c){
    someFunction(this.b, this.c)
}

Playground Link

  • Related