Crocsx
Crocsx

Reputation: 7609

No index signature with a parameter of type 'string' was found

I have an angular table where each row can contain sub cells

I defined the following interface

export interface TableCell {
  [key: string]: string | number
}

export interface TableRow {
  [key: string]: string | number | TableCell
}

I try to make a sorting function, where I use key and the nested key to filter elements like this

  private sort({ column, direction, subColumn }: TableSortEvent) {
    if (direction === '' || column === '') {
      return [...this.rows]
    } else {
      return [...this.rows].sort((a, b) => {
        const colA = a[column]
        const colB = b[column]
        if (
          (typeof colA === 'string' || typeof colA === 'number') &&
          (typeof colB === 'string' || typeof colB === 'number')
        ) {
          const res = this.compare(colA, colB)
          return direction === 'asc' ? res : -res
        }
        if (subColumn) {
          const subColA = colA[subColumn]
          const subColB = colB[subColumn]
          if (
            (typeof subColA === 'string' || typeof subColA === 'number') &&
            (typeof subColB === 'string' || typeof subColB === 'number')
          ) {
            const res = this.compare(subColA, subColB)
            return direction === 'asc' ? res : -res
          }
        }
        return 0
      })
    }
  }

So if a[column] is a string or number, I sort it, else I check the subKey.

It work nice but at build time I have the following

  No index signature with a parameter of type 'string' was found on type 'string | number | TableCell'.
      const subColB = colB[subColumn]

How can I fix this ?

export interface TableSortEvent {
  column: string
  subColumn?: string
  direction: TableSortDirection
}

Upvotes: 0

Views: 1279

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074335

Your objects don't have an index signature, so you can't just index into them with a string, it's not type-safe.

To handle that, you can use the keyof type operator, which lets you say that column is a valid key for the type of object you're sorting (and subColumn is a valid key for the subordinate object).

Without seeing more of your code it's hard to give you updated code, but for instance here's an example where we sort an object array by either a string or number property:

interface Foo {
    strCol: string;
    numCol: number;
}

const x: Foo[] = [
    { strCol: "1", numCol: 1 },
    { strCol: "2", numCol: 2 },
    { strCol: "3", numCol: 3 },
    { strCol: "4", numCol: 4 },
];

function sortBy(a: Foo[], col: keyof Foo) {
    a.sort((a, b) => {
        // Get the values from the objects as constants
        // Their type starts out as `string | number`.
        const avalue = a[col];
        const bvalue = b[col];
        if (typeof avalue === "string") {
            // Here, `avalue` is narrowed to `string`, and we can
            // safely assert that `bvalue` is `string` as well
            return avalue.localeCompare(bvalue as string);
        }
        // Here, `avalue` is narrowed to `number`, and we can
        // safely assert that `bvalue` is `number` as well
        return avalue - (bvalue as number);
    });
}

On the playground

Upvotes: 2

Related Questions