我有一个数组中的文件名列表。我的目标是读取数组中的所有文件,并将它们从字符串转换为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语句。错字。
答案 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
方法?
您看,reduce
是declared 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
的类型相同,无论出于何种原因,它都是编译器在没有类型时选择的声明明确给出,因此在您的代码中,initialValue
和previousValue
的类型与数组元素的类型相同 - {}
。
当你传递空数组[]
时,为什么它不会抱怨它何时需要空对象{}
?
因为空数组与它兼容 - 数组是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; }[]