Home > Blockchain >  Null-check for inherited member in TypeScript?
Null-check for inherited member in TypeScript?

Time:07-05

abstract class Base {
  protected id: number | null = null;

  init(id: number) {
    this.id = id;
  }

  isIdSet(_ = this.id): _ is null | never {
    if (this.id === null) throw new Error(ERROR_NO_ID);
    else return false;
  }
}

class Foo extends Base {
  private fetch(id: number) { ... }
  
  get(): Observable<string> {
    if (this.isIdSet()) {
      return this.fetch(this.id); // TS2322: Type 'number | null' is not assignable to type 'number'.
    }
  }
}

CodePudding user response:

TypeScript will be smart enough to narrow id's type to number if you check that it is not null on a variable defined inside the same function scope. Otherwise, it can't foresee the execution order and narrow the variable types.

get(): Observable<string> {
  const id = this.id; // number | null
  if (id !== null) {
    return this.fetch(this.id); // number
  }
}

CodePudding user response:

You may be looking for an assertion function.

abstract class Base {
  protected id: number | null = null;

  init(id: number) {
    this.id = id;
  }

  isIdSet(_ = this.id): asserts _ is number {
    if (this.id === null) throw new Error("ERROR_NO_ID");
  }
}

class Foo extends Base {
  private fetch(id: number) {}
  
  get() {
    this.isIdSet(this.id)
    return this.fetch(this.id);    
  }
}

Playground

CodePudding user response:

The idea was to put he null-check and throw into a function to get rid of duplicate if statements

You can do this in the base class with a custom getter that checks if this.m_id is defined and throws an error otherwise, essentially forcing the init method to be called before accessing id.

class Base {
    private m_id: number | null = null;

    protected get id(): number {
        if(this.m_id === null){
            throw new Error(`Id is not defined`);
        }
        return this.m_id;
    }

    public init(a_id: number): void {
        this.m_id = a_id;
    }
}


class Foo extends Base {
    private fetch(a_id: number): string {
        return a_id.toString();
    }

    public get(): string {
        return this.fetch(this.id);
    }
}

Playground

  • Related