网站搜索

如何让 TypeScript 推断函数的返回类型


我有这个 TypeScript 函数,用两种不同的方式编写:

    type Status = "pending_validation" | "ready_for_payment" | "paid"

    function colorStatus2(status: Status) {
        return {
            pending_validation: 'warning',
            ready_for_payment: 'inactive',
            paid: 'active',
        }[status];
    }

    function colorStatus(status: Status) {
        return status === 'pending_validation'
            ? 'warning'
            : status === 'ready_for_payment'
            ? 'inactive'
            : 'active';
    }

在第一种情况下,返回类型是string,但在第二种情况下,它是更具体的'warning' | 'inactive' | 'active'

有没有一种方法可以让 TypeScript 推断出第一个版本的返回类型,而不必让我指定它?

答案#1

TypeScript 的启发式类型推断决定,在对象字面量中,值为字符串字面量的属性应该被扩展为 string 类型的属性,而不是保持它们的字符串字面量类型。这是合理的,因为人们通常希望修改对象属性:

const val = {
    pending_validation: 'warning',
    ready_for_payment: 'inactive',
    paid: 'active',
};
/* const val: {
    pending_validation: string;
    ready_for_payment: string;
    paid: string;
} */
val.paid = "Active";
val.pending_validation = "Attention";

但是在你的情况下,这种推断对你没有帮助;你并不打算修改该对象字面量的属性。实际上,你把它当作一个常量或不可变对象来考虑。幸运的是,TypeScript 有一种方法可以告诉编译器你希望以这种方式对待一个值:const 断言:

const val = {
    pending_validation: 'warning',
    ready_for_payment: 'inactive',
    paid: 'active',
} as const; // <-- const assertion
/* const val: {
    readonly pending_validation: "warning";
    readonly ready_for_payment: "inactive";
    readonly paid: "active";
} */

现在编译器知道每个属性值将永远保持它最初创建时的字符串字面量。因此,当你对其进行索引时,你将获得你想要的那些字面类型:

function colorStatus(status: Status) {
    return ({
        pending_validation: 'warning',
        ready_for_payment: 'inactive',
        paid: 'active',
    } as const)[status];
}
// function colorStatus(status: Status): "warning" | "inactive" | "active"

代码的 Playground 链接