Como o filtro de uma Máquina de matriz com base no talvez-indefinido data-como-seqüência do item objeto de propriedade?

0

Pergunta

A API retorna o resultado como um objeto com mais de mil valores no seguinte formato:

result = {
  "items": [
            {
              "Name": "abc",
              "CreatedOn": "2017-08-29T15:21:20.000Z",
              "Description": "xyz"
            },
            {
              "Name": "def",
              "CreatedOn": "2021-05-21T15:20:20.000Z",
              "Description": "cvb"
            }
          ]
}

Eu gostaria de filtrar itens em um objeto, que são mais de 90 dias sem precisar iterar todos os itens usando o loop for. Em outras palavras, eu gostaria de fazer algo como esse abaixo, mas isto não funciona.

var currentDate = new Date();
var newResult = result.items?.filter(function(i) {
    return ((currentDate - Date.parse(i.CreatedOn)) > 90);
}

De acordo com o IDE de propriedade CreatedOn é do tipo string | undefined por isso lança o erro: Argumento do tipo 'string | undefined' não é atribuído ao parâmetro do tipo 'string'. Tipo 'undefined' não é atribuível ao tipo de 'string'.

javascript typescript
2021-11-24 03:43:04
3

Melhor resposta

2

Em algum lugar em seu projeto, você terá algo como isto:

interface Result {
    readonly items: readonly ResultItem[] | null;
}

interface ResultItem {
    readonly Name       : string;
    readonly CreatedOn  : string | undefined;
    readonly Description: string;
}

ou este (ou variações do mesmo):

type Result = {
    items?: ResultItem[];
}

interface ResultItem {
    Name       : string;
    CreatedOn? : string;
    Description: string;
}

Ou pode ser um type em vez de um interface (apenas certifique-se de que você nunca usa, class para descrever dados JSON, como JSON object dados não pode ser um class instância porque o construtor nunca é executado).

Além disso, você deve estar usando camelCase, não PascalCasepara propriedades de membro. Portanto, use nomes como createdOn em vez de CreatedOn em sua gerado JSON.

Felizmente, Você não precisa alterar os tipos de interfaces, basta alterar o TypeScript para segurança de seleção .CreatedOn e que Date.parse não retorno NaN. Assim:

  • O result.items ?? [] parte é por causa do seu post implica result.items é anulável ou talvez-undefined.
  • Nota quando utilizar map com um =>-função de estilo que você pode precisar para moldar objeto-literais em () assim, a JS motor não interpreta o { e } como delimitadores de bloco.
const result: Result = ...

const currentDate = new Date();

const newResult = (result.items ?? []).filter( e => {
    if( typeof e.CreatedOn === 'string' ) {
        const parsed = Date.parse( e.CreatedOn );
        if( !isNaN( parsed ) ) {
            return ( currentDate - parsed ) > 90;
        }
    }
    return false;
} );

Embora, pessoalmente, eu gostaria de fazê-lo com uma inicial filter e map passos:

const items       = result.items ?? [];
const currentDate = new Date();

const newResult = items
    .filter( e => typeof e.CreatedOn === 'string' )
    .map( e => ( { ...e, CreatedOn2: Date.parse( e.CreatedOn ) } ) )
    .filter( e => !isNaN( e.CreatedOn2 ) )
    .filter( e => ( currentDate - e.CreatedOn2 ) > 90 ) );

ou mais simplificadas:

const items       = result.items ?? [];
const currentDate = new Date();

const newResult = items
    .filter( e => typeof e.CreatedOn === 'string' )
    .map( e => Object.assign( e, { createdOn2: Date.parse( e.CreatedOn ) )
    .filter( e => !isNaN( e.CreatedOn2 ) && ( currentDate - e.CreatedOn2 ) > 90 );

Uma solução ainda melhor:

  • Se você está no controle de como o JSON é gerado, em seguida, você pode assegurar-se de que algumas (ou todas) as propriedades do item será sempre definida (e por isso nunca undefined ou null), assim se pode garantir que todas as 3 propriedades são sempre definidas (nunca null ou undefined), em seguida, atualizar a sua tipos/interfaces este:

    interface ResultItem {
        readonly name       : string;
        readonly createdOn  : string;
        readonly description: string;
    }
    
    • Nota o camelCase propriedades.
    • A imutabilidade dos dados é um benefício enorme, por isso certifique-se de que suas propriedades de interface são todos readonly, todas as matrizes são readonly T[]e que as propriedades são apenas anotado com ? ou | null ou | undefined como apropriado, em vez de simplesmente assumindo uma forma ou de outra.
  • Portanto, certifique-se de usar strictNullChecks em seu tsconfig.json ou tsc opções! - na verdade, é só usar strict sempre!

  • Também considere alterar seu JSON DTO do uso de um string representação de uma Data (há qualquer gurantees sobre o fuso horário?) para ser um nativamente legível Unix timestamp (em milissegundos), de que forma você pode evitar problemas com a Date.parse inteiramente:

por exemplo:

Resultado.cs:

public class ResultItem
{
    [JsonProperty( "createdOn" )]
    public DateTimeOffset CreatedOn { get; }

    [JsonProperty( "createdOnUnix" )]
    public Int64 CreatedOnUnix => this.CreatedOn.ToUnixTimeMilliseconds();
}

Resultado.ts:

interface ResultItem {
    readonly createdOn    : string;
    readonly createdOnUnix: number;
}
const ninetyDaysAgo = new Date();
ninetyDaysAgo.setDate( ninetyDaysAgo.getDate() - 90 );

const newResult = items.filter( e => new Date( e.createdOnUnix ) < ninetyDaysAgo );

...dessa forma, é uma única linha de trabalho.


O acima pode ser feita até mesmo mais simples como timestamps Unix são apenas números inteiros que são diretamente comparáveis, de modo new Date() pode ser evitado dentro do filterassim:

const ninetyDaysAgo = new Date();
ninetyDaysAgo.setDate( ninetyDaysAgo.getDate() - 90 );
const ninetyDaysAgoUnix = ninetyDaysAgo.getTime();

const newResult = items.filter( e => e.createdOnUnix < ninetyDaysAgoUnix );
2021-11-24 04:21:52
1

Supondo que você tenha interfaces definidas como este...

interface Item {
  Name: string,
  Description: string,
  CreatedOn?: string // note the optional "?"
}

interface Result {
  items?: Item[] // also optional according to your code
}

e você desejar filtrar os itens que são mais de 90 dias (excluindo aqueles que não CreatedOn) e, em seguida, tente isso

interface ItemWithDate extends Omit<Item, "CreatedOn"> {
  CreatedOn?: Date // real dates, so much better than strings
}

const result: Result = { /* whatever */ }

const items: ItemWithDate[] = result.items?.map(({ CreatedOn, ...item }) => ({
  ...item,
  CreatedOn: CreatedOn ? new Date(CreatedOn) : undefined
})) ?? []

const dateThreshold = new Date()
dateThreshold.setDate(dateThreshold.getDate() - 90)

const newItems = items.filter(({ CreatedOn }) =>
  CreatedOn && CreatedOn < dateThreshold)

Transcrito Playground Demo

2021-11-24 04:01:43

Perdoe a minha ignorância (e é um grande buraco de mina), o que ({ CreatedOn, ...item }) => ({ fazer, exatamente? Eu nunca vi a propagação do operador ... usado em uma lista de parâmetros de função ao mesmo tempo como um objeto literal.
Dai

@Dai extrai algumas propriedades nomeadas (CreatedOne mantém o resto em item. Basicamente um atalho para (obj) => { const { a, b, ...rest } = obj; ...
Phil
-1

o código está em falta ) de função de filtro

var currentDate = new Date();
var newResult = result.items?.filter(function(i) {
    return ((currentDate - Date.parse(i.CreatedOn)) > 90);
}  ) //<= misss


2021-11-24 04:23:03

Sua resposta não endereço tsc's tipo de erros.
Dai

Como está escrito, a sua resposta não é clara. Por favor, editar para adicionar outros detalhes que ajudarão as pessoas a compreender como este aborda a questão colocada. Você pode encontrar mais informações sobre como escrever boas respostas no centro de ajuda.
Community

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................