类型“{}”不能在map中键入'object []',而在typescript中可以减少

时间:2017-11-30 23:21:12

标签: angular typescript

我有一个数组中的文件名列表。我的目标是读取数组中的所有文件,并将它们从字符串转换为json 这是readAFile()API的签名。

readAFile(fileName: string, encoding: 'utf-8'): any {
  return fs.readFileSync(filename, {encoding: encoding});
}

现在,我有一个数组,其中包含要读取的所有文件的绝对路径files = ['/path/to/file1', '/path/to/file2', '/path/to/file3'] 我有另一个函数将此列表中的每个文件名映射到readAFile()并读取它们并将它们转换为JSON,如下所示:

readAllFiles(files: string[]): object[] {
  **return** files.map((aFile) => {
    return readAFile(aFile); // this api's return type is 'any'
  })
  .reduce((listOfJson, dataOfOneFile) => {
     const jsonData = JSON.parse(dataOfOneFile);
     listOfJson.push(jsonData);
     return listOfJson;
  }, []);
}

我想要包含文件名,这是我添加的内容

  files.map((aFile) => {
    const mappedData = {};  // Added this
    mappedData['data'] = readAFile(aFile); // the data now goes into this object
    mappedData['inputFile'] = aFile;
    return mappedData;    <------ ERROR: Type '{}' is not assignable to type 'object[]'.
  })

我认为解决此问题的简单方法是return [mappedData];。我不确定我是否正确理解这一点。有人可以帮我理解为什么这是一个错误?此外,欢迎任何其他建议 编辑1:在readAllFiles()中添加了缺少的return语句。错字。

1 个答案:

答案 0 :(得分:4)

return中的readAllFiles表达式非常复杂,很难看出错误的来源。我们将它分成中间部分:这里它的形式适合在typescript playground中查看和编译(我必须提供假fs声明,因为节点类型在那里不可用,还必须修复encoding}的readAFile参数:

declare var fs: { readFileSync(filename: string, { encoding: string }) };

function readAFile(fileName: string, encoding: string): any {
  return fs.readFileSync(fileName, {encoding: encoding});
}

function readAllFiles(files: string[]): object[] {
  const mf = files.map((aFile) => {
    const mappedData = {};  // Added this
    mappedData['data'] = readAFile(aFile, 'utf8'); // the data now goes into this object
    mappedData['inputFile'] = aFile;
    return mappedData; 
  });

  const rf = mf.reduce((listOfJson, dataOfOneFile) => {
     const jsonData = JSON.parse(dataOfOneFile); // <-- first error is here 
              // JSON.Parse expects string, but dataOfOneFile is an object now

     listOfJson.push(jsonData); // <-- and the real error is here
                // Property 'push' does not exist on type '{}'.
     return listOfJson;
  }, []);

  return rf;
}

为什么说Property 'push' does not exist on type '{}',当reduce的最后一个参数作为空数组给出时[],肯定它应该有push方法?

您看,reducedeclared as overloaded function with 2 variants

reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: ReadonlyArray<T>) => T,
        initialValue?: T): T;

reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: ReadonlyArray<T>) => U,
         initialValue: U): U;

第一个initalValue 与数组元素T的类型相同,无论出于何种原因,它都是编译器在没有类型时选择的声明明确给出,因此在您的代码中,initialValuepreviousValue的类型与数组元素的类型相同 - {}

当你传递空数组[]时,为什么它不会抱怨它何时需要空对象{}

因为空数组与它兼容 - 数组是javascript中的对象,空对象根本没有属性,所以任何数组都可以分配给它。

如何让reduce返回不同的类型?

您可以告诉编译器您想要第二个reduce变体 - 具有不同initialValue类型的变体。如果您希望它为object[],则可以将其作为reduce的显式通用参数提供:

 const rf = mf.reduce<object[]>((listOfJson, dataOfOneFile) => {

但是,当你没有真正将列表缩减为单个值时,为什么使用reduce呢?如果您需要从列表中创建另一个列表,单个map就可以了:

function readAllFiles(files: string[]) {
  return files.map((aFile) => {
    return {
      data: JSON.parse(readAFile(aFile, 'utf8')),
      inputFile: aFile
    }
  });
}

该类型推断为

function readAllFiles(files: string[]): { data: any; inputFile: string; }[]