Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

107
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda