I am puzzled as to why my function's return type transforms into a promise when I interact with the cell.value or use console.log

Recently, I embarked on the journey of coding a validation process for my Excel Sheet. To keep the code concise, I implemented it in a straightforward manner.

Here is a snippet of my source code:

function main(workbook: ExcelScript.Workbook) {

  console.log("starting...");
  let cs = createVariantCategorySheet(workbook.getWorksheet("variant categories"));
  cs.validateSheet();
  for (let m of cs.logMessages) {
    console.log(m);
  }
  console.log("finished...");
}

function createVariantCategorySheet(worksheet: ExcelScript.Worksheet): ImportSheet {

  let sheet = new ImportSheetBuilder()
    .name("variant categories")
    .index(1)
    .worksheet(worksheet)
    .addColumnInfo(
      new ColumnInfoBuilder()
        .index(4)
        .name("Sort Order")
        // .addChecker(new NotEmptyChecker())
        .addChecker(new UniqueSortOrderChecker(worksheet, worksheet.getRange("B:B")))
      .build()
    )
    .build();
  return sheet;
}


class ImportSheet {
  public name: string;
  public index: number;
  public worksheet?: ExcelScript.Worksheet
  columns: ColumnInfo[];
  public logMessages: string[];

  constructor() {
    this.index = -1;
    this.name = "";
    this.columns = [];
    this.logMessages = [];
  }

  // ... Some useful private methods ...

  validateSheet() {
    let rowCount = this.getRowCount();

    for (let rowIndex = 1; rowIndex < rowCount; rowIndex++) {      
      if (this.isRowEmpty(rowIndex)) {
        this.logMessages.push("no more lines... ")
        return;
      }
      this.validatingRow(rowIndex);
    }
  }

  private validatingRow(rowIndex: number) {
    this.logMessages.push("iterating over line [" + rowIndex + "]")
    for (let columnItem of this.columns) {
      this.validatingColumn(columnItem, this.rangeToValidate(rowIndex, columnItem.index));
    }
  }

  private validatingColumn(columnItem: ColumnInfo, rangeToValidate: ExcelScript.Range){
    for (let validator of columnItem.validator) {
      let stringToValidate = rangeToValidate.getValue().toString();
      this.logMessages.push("###### " + validator.isValid)
      if (!validator.isValid(stringToValidate, rangeToValidate.getRowIndex())) {
        this.logMessages.push("## ## ERROR: Failed Validation " + validator.getName() +
          " in '" + rangeToValidate.getAddress() + "' for column '" +
          columnItem.name + "'.");
      } else {
        this.logMessages.push("## ## INFO: Success Validation " + validator.getName() +
          " in '" + rangeToValidate.getAddress() + "' for column '" +
          columnItem.name + "'.");
      }
    }
  }
}

class ColumnInfo {
  name: string;
  index: number;
  validator: Checker[];
}

interface Checker {
  isValid(value: string, rowIndex: number): boolean
  getName(): string
}

class NotEmptyChecker implements Checker {

  isValid(value: string): boolean {
    if (value)
      return true;
    else
      return false;
  }

  getName(): string {
    return NotEmptyChecker.name;
  }
}

class UniqueSortOrderChecker implements Checker {
  sortOrderMap: Map<string, Set<string>>;

  range: ExcelScript.Range
  worksheet: ExcelScript.Worksheet

  constructor(worksheet: ExcelScript.Worksheet, range: ExcelScript.Range) {
    this.range = range;
    this.worksheet = worksheet;
    this.sortOrderMap = new Map<string, Set<string>>();
  }

  isValid(value: string, rowIndex: number): boolean {
    return true;
  }

  getName(): string {
    return UniqueSortOrderChecker.name;
  }
}

I decided to omit the Builders as they mainly focus on object creation.

The provided code effectively achieves the file validation as intended.

However, when attempting to tweak the UniqueSortOrderChecker method like so:

  isValid(value: string, rowIndex: number): boolean {
    console.log("test");
    return true;
  }         

The resulting transformation impacts the generated code significantly, leading to a promise-based return:

function (value, rowIndex) {
                            return __awaiter(this, void 0, void 0, function () {
                                return __generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0:
                                            ExcelScript.engine.traceLine(264);
                                            return [4 /*yield*/, console.log("test")];
                                        case 1:
                                            (_a.sent());
                                            ExcelScript.engine.traceLine(undefined);
                                            return [2 /*return*/, true];
                                    }
                                });
                            });
                        }  

A similar outcome emerges when trying to extract cell value with:

  isValid(value: string, rowIndex: number): boolean {
    let cellValue = this.range.getRow(rowIndex).getValue().toString();
    return true;
  }

This change also results in a promisify return type:

function (value, rowIndex) {
                            return __awaiter(this, void 0, void 0, function () {
                                var cellValue;
                                return __generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0:
                                            ExcelScript.engine.traceLine(264);
                                            return [4 /*yield*/, this.range.getRow(rowIndex).getValue()];
                                        case 1:
                                            cellValue = (_a.sent()).toString();
                                            ExcelScript.engine.traceLine(undefined);
                                            return [2 /*return*/, true];
                                    }
                                });
                            });
                        }

If anyone has encountered a similar issue or can provide guidance, your insight would be greatly appreciated. The shift to a promise-based system seems to be affecting the validation results adversely.

Thank you for taking the time to read through the details provided above.

Answer №1

By leveraging intricate underlying mechanisms, Office Script is able to give the illusion of synchronous execution to inherently asynchronous code.

Starting from 2021-07-01, every Office Script method, including console.log, now returns a promise, as you may have noticed!

This sophisticated system strategically places awaits within the code to ensure compatibility with IntelliSense and simulate synchronous behavior.

While most common scenarios are covered by this mechanism as of 2021-07-01, there are still some exceptions where the complex transformation logic may fall short.

Currently, utilizing Office Script methods and console.log in class methods is not supported.

If you find yourself needing to use these features in classes, simply mark those class methods as async and await their completion.

If this functionality is crucial for your particular situation, I would suggest providing feedback directly through the Office Script Editor by clicking on ... and selecting Send Feedback.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I am looking to replicate a DOM element using Angular 4

I am interested in creating a clone of a DOM element. For example, if I have the following structure: <div> <p></p> <p></p> <p></p> <p></p> <button (click)="copy()"></button> & ...

What is the process for initializing the default/prefilled value of an input element within a mat-form-field when the page loads?

I'm looking to create an HTML element where the default data (stored in the variable 'preselectedValue') is automatically filled into the input field when the component loads. The user should then be able to directly edit this search string. ...

`Creating a union of prop types in TypeScript and React`

I'm facing an issue with a component prop that I need to restrict to specific strings using a union type, as shown below: type HeadingProps = { level?: 'h1' | 'h2' | 'h3' | 'h4'| 'h5' | 'h6&a ...

Prisma causing a compiler error

Currently, I am in the process of developing a project that integrates a GraphQL server and utilizes Prisma to establish a connection with the database. Additionally, I have chosen to implement this project using TypeScript. Unfortunately, as I compile my ...

Accurate TS declaration for combining fields into one mapping

I have a data structure called AccountDefinition which is structured like this: something: { type: 'client', parameters: { foo: 3 } }, other: { type: 'user', parameters: { bar: 3 } }, ... The TypeScript declaration ...

What is the best way to choose an element within a component's template?

Is there a way to access an element that is defined in a component template? While Polymer has the $ and $$ to make this task simple, I am curious about how it can be done in Angular. Consider the example provided in the tutorial: import {Component} from ...

I'm having trouble setting a value for an object with a generic type

I am attempting to set a value for the property of an object with generic typing passed into a function. The structure of the object is not known beforehand, and the function receives the property name dynamically as a string argument. TypeScript is genera ...

Looking to resolve a module-specific error in Angular that has not been identified

While practicing Angular, I encountered an error during compilation: Module not found: Error: Can't resolve './app.component.css' in 'D:\hello-world-app\src\app' i 「wdm」: Failed to compile. This is my app.compo ...

When upgrading from ng15 to ng16, beware of the error message stating that the type '(event: RouterEvent) => void' cannot be assigned to type '(value: Event_2) => void.'

section, I encountered issues with my Angular project after upgrading from ng15 to ng16. Specifically, errors are arising when trying to implement the code snippet below. Can anyone provide insights on what may be causing problems with the event argument ...

Tips for implementing the handleChange event with CalendarComponent from the PrimeReact library

Hey there! I'm currently working with the CalendarComponent from the PrimeReact library in my app. I want to update the type of event being typed in the handleChange function instead of leaving it as :any. Can anyone provide some suggestions on what s ...

What is the best way to simulate global variables that are declared in a separate file?

dataConfiguration.js var userData = { URIs: { APIURI: "C" }, EncryptedToken: "D" }; configSetup.js config.set({ basePath: '', files:['dataConfiguration.js' ], ..... UserComponentDetails: .....some i ...

React TypeScript error: Cannot access property "x" on object of type 'A | B'

Just starting out with react typescript and I've encountered the following typescript error when creating components: interface APIResponseA { a:string[]; b:number; c: string | null; // <- } interface APIResponseB { a:string[] | null; b:number; d: ...

How can I conceal the word "null" within an Angular 2 input field?

Whenever there is a null value in the JSON, it ends up displaying in the input field. How do I go about hiding it so that only the name shows up instead? <div> <input type="hidden" name="roleUserHidden-{{roleIndex}}" #role ...

Why is TypeScript giving an error about an undefined object key, even though the key was assigned a value in the previous command?

type MaybeThereIsAValue = { [p: string]: string | undefined } ... let bar: MaybeThereIsAValue = {}; const key = "carpe"; bar[key] = "diem"; const why = bar[key]; // why is string | undefined I am confused as to why why is showing ...

Attempting to simulate the behavior of Angular2 Token during testing

Currently, I am working on obtaining a token that is required for API authentication to retrieve a list. My approach begins with importing the angular2-token library: import { Angular2TokenService } from 'angular2-token'; After this, I include ...

The Word Document is unable to locate the module or its associated type declarations

Encountering an issue while attempting to import a file from the src/assets/documents directory. https://i.sstatic.net/Gxq05.png Currently working on a React Project using Typescript. The goal is to import a file and use its value within an anchor tag fo ...

How to Position Logo in the Center of MUI AppBar in React

I've been struggling to center align the logo in the AppBar. I can't seem to get the logo to be centered both vertically and horizontally on its own. Here is my code from AppBar.tsx: import * as React from 'react'; import { styled, useT ...

Adding a condition to the react-router v6 element: A step-by-step guide

I am currently in the process of updating my project from v5 to v6 of react-router-dom. However, I have encountered an issue. Everything was working fine in v5 <Route path={`${url}/phases/:phaseIndex`}> {(chosenPhase?.type === PhaseTy ...

Jest - managing parent class methods during unit tests

The code snippet provided demonstrates a class called First extending TelemetryFramework with specific props and states, containing a method named getData. This method retrieves confidential data and logs telemetry information. However, running unit tests ...

Mastering the art of accessing properties in typescript post implementing Object.defineProperty

I was experimenting with the TypeScript playground trying to figure out decorators and encountered some questions. class PathInfo { functionName: string; httpPath: string; httpMethod: string; constructor(functionName: string, httpPath: str ...