typescript 可以通过const类型参数捕获varargs吗?

mec1mxoz  于 2023-05-01  发布在  TypeScript
关注(0)|答案(1)|浏览(105)

5.0引入了const类型参数。是否可以通过这样的类型参数捕获varargs?
下面的函数尝试这样做:

function insertIf<const V extends any[]>(condition: boolean, ...value: V): V | readonly [] {
    if (condition) {
        return value;
    } else {
        return [];
    }
}

不幸的是,返回类型总是派生为any[] | readonly [],而不管给函数的实际参数是什么。
示例调用为insertIf(true, { s: 'a' }, { s: '?'})

yzuktlbb

yzuktlbb1#

您应该将V上的约束从any[]更改为readonly数组类型,如readonly any[]

function insertIf<const V extends readonly any[]>(
    condition: boolean, ...value: V
): V | readonly [] {
    if (condition) { return value; } else { return []; }
}

const x = insertIf(true, { s: 'a' }, { s: '?' });
// const x: readonly [] | readonly [{ readonly s: "a"; }, { readonly s: "?"; }]

microsoft/TypeScript#51865的描述中,实现const类型参数的pull请求说:
const类型参数被约束为数组类型时,该数组类型应包含readonly修饰符;否则,类型参数的推断将不能满足约束。
对于你的原始版本:

function insertIf<const V extends any[]>(
    condition: boolean, ...value: V
): V | readonly [] {
    if (condition) { return value; } else { return []; }
}

const x = insertIf(true, { s: 'a' }, { s: '?' });
// const x: any[] | readonly []

编译器实际上希望在这里将V推断为readonly [{ readonly s: "a"; }, { readonly s: "?"; }],就像您使用了constAssert一样。但该类型 * 不可 * 分配给any[];与普通读写阵列相比,只读阵列具有较少的已知方法。
因此,推断步骤失败,编译器福尔斯到any[]的约束,该约束通过了类型检查,您的代码看起来像是无声的失败。
这绝对是一个混乱的点,之前已经被报告为一个bug,参见microsoft/TypeScript#51931,如果编译器以某种方式警告你const修饰符不会很好地工作,但至少现在这是按预期工作的,解决方案是添加readonly修饰符。
Playground链接到代码

相关问题