在解构赋值之前声明对象 属性 类型

Declaring object property types before destructuring assignment

假设有一个函数 returns 一个对象,其 属性 类型可以被推断或明确提供:

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

然后我们可以解构返回的对象并分配给新变量:

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

一切都很好,花花公子。现在让我们假设我们稍后需要重新分配给那些相同的变量,更具体地说是在 switch 语句中。为了防止 Cannot redeclare block-scoped variable 'xyz'. ts(2451) 我们将利用 assignment without declaration 并像这样进行:

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);
}

那么问题是,当我知道 declare/extract my_amy_b 等类型时,我知道它们将是什么并且不想手动把它们打出来? Here's a playground snippet.


详细说明

我正在寻找的是一种在我使用

初始化变量时声明类型的方法
let my_a, my_b, my_c;

根据我对myFn签名的了解,以防止

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

您可以声明一个接口并将您的开关逻辑放在匿名箭头函数中:

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);
        }
}

如果您只想提前显式键入 my_* 变量,那么您可以通过钻取函数的 return 类型来实现。

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

typeof myFnmyFn 获取函数类型,因此类型系统可以使用它。 ReturnType<...> 将获得函数 returns 的类型。最后,['a'] 将从 return 类型中获取 a 属性。

Playground


但这并不是真正需要的。您的 playground 片段可以正确推断出所有内容,并且不会引发类型错误。所以我会考虑这是否真的有必要。