Justin Reusch
Justin Reusch

Reputation: 654

Using TypeScript Type Predicates on private properties

I have a class which has a private, optional property (private foo?: Foo). Within the private code of the class, I need to be able to validate that this property exists, so that I can handle failure once at the beginning of the method and then deal with it as non-optional in the rest of the block.

The code below works like a charm if foo is public. However, since I need foo to be private, it doesn't work. Instead of validating this as conforming to FooBar & FooContainer, the type of this becomes never.

This behavior totally makes sense for public usage where I don't want to allow external code to validate the existence of a private property. However, I am trying to find a type-predicate-like solution I can use privately within my class to make the property in question non-optional.

interface Foo {
    bar: string;
}

interface FooContainer {
    foo: Foo;
}

class FooBar {
    private foo?: Foo;
    bar?: string

    constructor(foo?: Foo, bar?: string) {
        this.foo = foo;
        this.bar = bar;
    }

    private isFooContainer(): this is FooContainer {
        const { foo } = this;
        return typeof foo !== "undefined";
    }
    
    printFoo() {
        if (!this.isFooContainer()) throw new Error("There is no foo!!!!");
        // For the rest of this method `this.foo` should be typed as `Foo` rather than `Foo | undefined`
        console.log(this.foo.bar); // <--- No optional chaining (`this.foo?.bar`) required here.`
    }
}

Upvotes: 2

Views: 532

Answers (1)

cefn
cefn

Reputation: 3321

Is it as simple as inlining the check itself? I wonder if I've missed the purpose of having an interface and a predicate but this seems fine to me...

interface Foo {
    bar: string;
}

class FooBar {
    #foo?:Foo;
    bar?:string;

    constructor(foo?:Foo, bar?:string) {
        this.#foo = foo;
        this.bar = bar;
    }
    
    printFoo() {
        if(typeof this.#foo === "undefined") throw new Error("There is no foo!!!!");
        console.log(this.#foo.bar); 
    }
}

Typescript Playground

Upvotes: 1

Related Questions