0

我正在尝试使用SheetJS库设置来自 .xlsx 的值。下面我将在我尝试过的表格之后展示代码和错误。

var dataToJson的数据输出:

(6) [{…}, {…}, {…}, {…}, {…}, {…}]
0: {idSeller: 503, idSupplier: 20, financialGoal: 0, positivationGoal: 300, qtVenda: 0, …}
1: {idSeller: 3113, idSupplier: 9, financialGoal: 400000, positivationGoal: 6, qtVenda: 0, …}
2: {idSeller: 7303, idSupplier: 378, financialGoal: 390000, positivationGoal: 0, qtVenda: 0, …}
3: {idSeller: 3113, idSupplier: 964, financialGoal: 360000, positivationGoal: 0, qtVenda: 0, …}
4: {idSeller: 7116, idSupplier: 378, financialGoal: 310000, positivationGoal: 0, qtVenda: 0, …}
5: {idSeller: 7117, idSupplier: 378, financialGoal: 300000, positivationGoal: 0, qtVenda: 0, …}
length: 6
__proto__: Array(0)

对象内的数据:

5:
financialGoal: 300000
idSeller: 7117
idSupplier: 378
positivationGoal: 0
qtVenda: 0
__rowNum__: 6
__proto__: Object

接口和代码:

interface IXlsxData {
  financialGoal: number;
  idSeller: number;
  idSupplier: number;
  positivationGoal: number;
  qtVenda: number;
  // __rowNum__: number;
};
    
const Archive: React.FC = () => {
  const [files, setFiles] = useState<IXlsxData>(null);
    
  const readExcel = (e) => {
    e.preventDefault();
    
    var file = e.target.files[0];
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);
    
    reader.onload = (e) => {
    /* Parse data */
    let data = e.target.result;
    let readedData = XLSX.read(data, {type: 'buffer'});
    
    /* Get first ws (worksheet) */
    const wsname = readedData.SheetNames[0];
    const ws = readedData.Sheets[wsname];

    /* Convert array to json */
    const dataToJson = XLSX.utils.sheet_to_json(ws);
    setFiles(dataToJson); // ---- ERROR ----
    // setFiles([...files, dataToJson]);
  };
}

错误:

const dataToJson: unknown[]
Argument of type 'unknown[]' is not assignable to parameter of type 'SetStateAction<IXlsxData[]>'.
  Type 'unknown[]' is not assignable to type 'IXlsxData[]'.
    Type '{}' is missing the following properties from type 'IXlsxData': financialGoal, idSeller, idSupplier, positivationGoal, qtVendats(2345)

我已经尝试了几种方法:

interface IXlsxData {
  [index: number]: { 
    financialGoal: number;
    idSeller: number;
    idSupplier: number;
    positivationGoal: number;
    qtVenda: number;
  };
}

还有这个:

interface IXlsxProps extends Array<IXlsxData> {};
const [files, setFiles] = useState<IXlsxProps>([]);
4

1 回答 1

0

这个定义IXlsxData很好:

// you dont have to include ALL the existing fields here
// just the ones you're going to use later in the code
interface IXlsxData {
  financialGoal: number;
  idSeller: number;
  idSupplier: number;
  positivationGoal: number;
  qtVenda: number;
};

但是,如果您期望这些值的数组(正如我可以通过第一个日志猜到的那样),您必须useState像这样注释:

const [files, setFiles] = useState<IXlsxData[]>([]);

现在到了真正的问题。问题是XLSX.utils.sheet_to_json(ws)返回一个带有 type 的值,unknown[]但您setFiles期望一个带有 type 的值IXlsxData[]。现在您有几个选项来确保编译器返回的结果sheet_to_json是所需的类型:

function isIXlsxData(data: unknown): data is IXlsxData {
  return (data != null)
      && (typeof data === 'object')
      && (typeof (data as IXlsxData).financialGoal === 'number')
      && (typeof (data as IXlsxData).idSeller === 'number')
      && (typeof (data as IXlsxData).idSupplier === 'number')
      && (typeof (data as IXlsxData).positivationGoal === 'number')
      && (typeof (data as IXlsxData).qtVenda === 'number');
}

function isArrayOfIXlsxData(data: unknown): data is IXlsxData[] {
  if (!Array.isArray(data)) return false;
  
  return data.every(isIXlsxData);
}

const dataToJson = XLSX.utils.sheet_to_json(ws);
if (isArrayOfIXlsxData(dataToJson)) {
  setFiles(dataToJson);
} else {
  // handle error
}

虽然类型保护为您提供了一个简单的答案yesno问题:该unknown[]类型是否实际上是您的IXlsxData[]. 断言函数可能会为您提供更多关于究竟出了什么问题的信息:

function assertIXlsxData(data: unknown): asserts data is IXlsxData {
  if (data == null) {
    throw new Error('IXlsxData assert failed: value is null');
  }
  if (typeof data !== 'object')
    throw new Error('IXlsxData assert failed: value is not an object');

  const errors: string[] = [];
  (['financialGoal', 
    'idSeller', 
    'idSupplier', 
    'positivationGoal', 
    'qtVenda',
  ] as const).forEach((prop) => {
      if (typeof (data as IXlsxData)[prop] !== 'number') {
        errors.push(`property ${prop} must be a number`);
      }
  })

  if (errors.length > 0) 
    throw new Error(`IXlsxData assert failed: ${errors.join(', ')}`)
}

function assertArrayOfIXlsxData(data: unknown): asserts data is IXlsxData[] {
  if (!Array.isArray(data)) 
    throw new Error('IXlsxData[] assert failed. Data is not an array');
  
  data.forEach(assertIXlsxData);
}

const dataToJson = XLSX.utils.sheet_to_json(ws);
try {
  assertArrayOfIXlsxData(dataToJson);
  setFiles(dataToJson);
} catch (ex) {
  // handle error
}
  • 我知道更好的方法:输入 assertion。您可能会承担责任,如果您绝对确定没有其他任何东西,但IXlsxData[]曾经来自此sheet_to_json(ws)调用,只需强制编译器相信您:
const dataToJson = XLSX.utils.sheet_to_json(ws) as IXlsxData[];
setFiles(dataToJson);
于 2021-06-10T21:12:41.523 回答