Joe - Check out my books
Joe - Check out my books

Reputation: 16895

Declaring object property types before destructuring assignment

Let's assume there's a function that returns an object whose property types can either be inferred or are explicitly provided:

const myFn = (arg: number) => {
    return {
        a: 1 + arg,
        b: 'b' + arg,
        c: (() => { return arg + 'c'})()
    }
}

We can then destructure the returned object and assign to new variables:

const { a, b, c } = myFn(10);
console.log('used once', a, b, c);

All nice and dandy. Now let's assume we'll need to reassign to those same variables later on, more specifically in a switch statement. In order to prevent Cannot redeclare block-scoped variable 'xyz'. ts(2451) we'll take advantage of assignment without declaration and proceed like so:

let my_a, my_b, my_c;

switch (true) {
    case Math.random() < 0.5:
        ({a: my_a, b: my_b, c: my_c} = myFn(Math.random()));
        console.log('called at one point', my_a, my_b, my_c);
    default:
        ({a: my_a, b: my_b, c: my_c} = myFn(Math.random()));
        console.log('called at another point', my_a, my_b, my_c);
}

The question is then, how can I declare/extract the types of my_a, my_b etc when I know what they're going to be and don't want to manually type them out? Here's a playground snippet.


ELABORATION

What I'm looking for is a way to declare the types when I initialize the vars using

let my_a, my_b, my_c;

based on what I know about the signature of myFn to prevent

Variable 'my_a' implicitly has an 'any' type,
but a better type may be inferred from usage. ts(7043)

Upvotes: 0

Views: 805

Answers (2)

Alex Wayne
Alex Wayne

Reputation: 186994

If you just want to explicitly type the my_* variables ahead of time, then you can do that by drilling into the return type of your function.

let my_a: ReturnType<typeof myFn>['a'],
    my_b: ReturnType<typeof myFn>['b'],
    my_c: ReturnType<typeof myFn>['c'];

typeof myFn gets the function type from the myFn so the type system can work with it. ReturnType<...> will get the type that function returns. And, lastly, ['a'] will get the a property from that return type.

Playground


This isn't really required though. Your playground snippet infers everything correctly and raises no type errors. So I would think about whether this is really necessary.

Upvotes: 2

Ovidijus Parsiunas
Ovidijus Parsiunas

Reputation: 2732

You can declare an interface and place your switch logic inside anonymous arrow functions:

interface Alphabet {
    a: number,
    b: string,
    c: string,
}

const myFn = (arg: number): Alphabet =>  {
    return {
        a: 1 + arg,
        b: 'b' + arg,
        c: (() => { return arg + 'c'})()
    }
}

let my_a, my_b, my_c;

switch (true) {
    case Math.random() < 0.5:
        () => {
            const {a: my_a, b: my_b, c: my_c}: Alphabet = myFn(Math.random());
            console.log('called at one point', my_a, my_b, my_c);
        }
    default:
        () => {
            const {a: my_a, b: my_b, c: my_c}: Alphabet = myFn(Math.random());
            console.log('called at one point', my_a, my_b, my_c);
        }
}

Upvotes: 2

Related Questions