Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

108
Vistas
TypeScript set type for array of objects causes problem when sorting with localCompare

I got a simple function with an array of objects. On this array there will always be at least one string property.

In the body I want to dinamically be able to select that string by key and order with localCompare.

The problem is that the properties can have numbers and when doing localCompare TS complains.

;(() => {
  type entries = {
    [key: string]: string | number
  }


  const data: entries[] = [
    { key: 'bbb', number: 1 }, 
    { key: 'aaa', number: 2}
  ]
  // Let's imagine index comes as a parameter
  const index = 'key'
  const order: entries[] = data.sort((a, b) => a[index].localeCompare(b[index]))

  console.log(order)
})()

Link to TS playground

about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

Just make sure you always convert the properties to strings:

;(() => {
  type entries = {
    [key: string]: string | number
  }


  const data: entries[] = [
    { key: 2, number: 4 },
    { key: 'bbb', number: 1 }, 
    { key: 'aaa', number: 2}, 
    { key: 1, number: 3}
  ]

  const index = 'key'
  const order: entries[] = data.sort((a, b) =>
      `${a[index]}`.localeCompare(`${b[index]}`))

  console.log(order)
})()

Or, check the type of the values:

;(() => {
  type entries = {
    [key: string]: string | number
  }


  const data: entries[] = [
    { key: 'bbb', number: 1 }, 
    { key: 'aaa', number: 2}
  ]

  const index = 'key'
  const order: entries[] = data.sort((a, b) => {
      const valA = a[index];
      const valB = b[index];

      return typeof valA === 'number' && typeof valB === 'number'
          ? valA - valB
          : `${valA}`.localeCompare(`${valB}`);
  });

  console.log(order)
})()

about 4 years ago · Juan Pablo Isaza Denunciar

0

Based on your comments, I think you're saying that you know that a[index] will always be a string because of logic in your code, but the problem is that TypeScript doesn't know that (because the object signature says it can be a string or a number).

To reassure TypeScript, you have at least a couple of choices:

Use a type assertion function:

function assertIsString(value: any): asserts value is string {
   if (typeof value !== "string") {
       throw new Error(`Expected a string, but got ${typeof value}`);
   }
}

Then:

const order: entries[] = data.sort((a, b) => {
    const avalue = a[index];
    const bvalue = b[index];
    assertIsString(avalue);
    assertIsString(bvalue);
    return avalue.localeCompare(bvalue);
});

Updated playground

This also has the advantage of giving you an explicit error if your code fails to ensure that the property name is only the name of a string property.

Use a type assertion

If you don't want the (very minimal) overhead of the assertion function, you can just override TypeScript:

const order: entries[] = data.sort((a, b) => (a[index] as string).localeCompare(b[index] as string));

Updated playground

Both

If you know your objects are homogenous, you can combine the two approaches, for instance using the assertion function just on the first entry:

if (data.length > 1) {
    assertIsString(data[0][index]);
}
const order: entries[] = data.sort((a, b) => (a[index] as string).localeCompare(b[index] as string));

Updated playground

That way you get a nice explicit error, but you don't have the overhead of checking during the sort.

about 4 years ago · Juan Pablo Isaza Denunciar

0

Your TS doesn't follow the TS guidelines.

Here I made a function sortByProp, which uses keyof so you can easily select the property you want to use for your sort.

You can try the code here: Playground.

When I find out how to filter the types of properties, I will update the code again.

interface Entrie {
  key: string;
  number: number | string;
  random?: boolean;
}

// Used so I can filter the keys by the type I want. In this case string | number;
type FilteredKeys<T, U> = { [P in keyof T]: T[P] extends U ? P : never }[keyof T];

const data: Entrie[] = [
  { key: 'bbb', number: 1 },
  { key: 'aaa', number: 3 },
  { key: 'aba', number: 2 }
];


function sortByProp<T, F>(arr: T[], prop: FilteredKeys<T, F>) {
  if (typeof prop == 'string') return arr.sort((a, b) => {
    if (a[prop] < b[prop]) return -1;
    if (a[prop] > b[prop]) return 1;
    return 0;
  });
  return arr.sort((a: any, b: any) => a[prop] - b[prop]);
}

console.log("SortByKey:", sortByProp<Entrie, string | number>(data, "key"));
console.log("SortByNumber:", sortByProp<Entrie, string | number>(data, "number"));
about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda