typescript TS允许字符串是字符串数组吗?

kkbh8khc  于 2023-02-20  发布在  TypeScript
关注(0)|答案(1)|浏览(142)

我已经把问题缩小到下面的代码,它应该返回一个从字符串到字符串数组的Map,然而,在我的reducer中,我创建了一个从字符串到字符串的Map,并且TypeScript编译代码片段没有错误:

const parseFeatures = (featSpecs: string[]): Record<string, string[]> =>
  featSpecs.map(f => f.split("=", 2))
  .reduce((acc, [k, v]) => {
    // v is a string, so why does this compile?
    return {...acc, [k]: v};
  }, {});

  
console.log(parseFeatures(["foo=bar", "baz=qux,stuff,thing"]))

// correctly doesn't compile: Type 'string' is not assignable to type 'string[]'.
// const foo: Record<string, string[]> = {"foo": "bar"}

在TS playground中运行该代码片段,输出如下:

{
  "foo": "bar",
  "baz": "qux,stuff,thing"
}

这显然不是一个从字符串到字符串数组的Map!我如何让TypeScript正确地对我的reducer进行类型检查?我希望这个代码段发出错误。

t2a7ltrp

t2a7ltrp1#

这里的问题是你给reduce函数提供了一个空文本,返回类型是从初始值的类型推断出来的,因此. reduce()返回的{}是可赋值的。
您可以通过定义init值的类型来修复它:

function parseFeatures(featSpecs: string[]): Record<string, string[]> {
    const init: Record<string, string[]> = {}
    return featSpecs
        .map(f => f.split("=", 2))
        .reduce((acc, [k, v]) => {
            // this return vallue does not fit the init value type
            return { ...acc, [k]: v };
        }, init);
}

将为您提供所需的错误:
过载2/3,'(回调fn:(先前值:记录〈字符串,字符串[]〉,当前值:字符串[],当前索引:编号,数组:字符串[][])=〉记录〈字符串,字符串[]〉,初始值:记录〈字符串,字符串[]〉):记录""出现以下错误。类型""的参数(acc:<...>记录〈字符串,字符串[]〉,元素:字符串[])=〉{[ x:字符串]:字符串字符串[];}"不能赋给类型为""的参数(previousValue:|记录〈字符串,字符串[]〉,当前值:字符串[],当前索引:编号,数组:字符串[][])=〉记录〈字符串,字符串[]〉"。键入"{[ x:字符串]:字符串string [];}"不能赋给类型" Record〈string,string []〉"。" string "索引签名不兼容。键入" string|string []"不能赋给类型" string []"。| string[]' is not assignable to type 'string[]'.**
TS类型可能只是描述了一个子集,所以如果你在{}中添加了一个属性,TS仍然会认为它是安全的,因为你在添加属性之后就不能访问它了,而{}只是一个空记录,所以没有问题。

相关问题