Come filtro un Dattiloscritto matrice di base che forse non definita data come stringa elemento oggetto di proprietà?

0

Domanda

L'API restituisce il risultato come un oggetto con più di un migliaio di valori nel seguente 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"
            }
          ]
}

Vorrei filtrare gli elementi in oggetto, che sono più di 90 giorni, senza dover scorrere tutti gli elementi utilizzando il ciclo for. In altre parole, mi piacerebbe fare qualcosa di simile a questo qui sotto, ma questo non funziona.

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

Secondo l'IDE di proprietà CreatedOn è di tipo string | undefined così si genera l'errore: Argomento di tipo 'string | undefined' non è assegnabile al parametro di tipo 'string'. Tipo 'undefined' non è assegnabile al tipo di 'string'.

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

Migliore risposta

2

Da qualche parte nel vostro progetto avrete qualcosa di simile a questo:

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

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

o questo (o sue varianti):

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

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

Oppure potrebbe essere un type invece di un interface (solo assicurarsi che non si utilizza mai class per descrivere i dati JSON, come JSON object i dati non possono essere un class istanza perché il costruttore non viene mai eseguita).

Inoltre, si dovrebbe essere utilizzando camelCasenon PascalCaseper le proprietà del membro. Quindi, utilizzare nomi come createdOn invece di CreatedOn nel tuo generato JSON.

Fortunatamente non c'È bisogno di cambiare i tipi di interfacce, basta cambiare il Dattiloscritto di sicurezza check .CreatedOn e che Date.parse non ritorno NaN. In questo modo:

  • Il result.items ?? [] perché il tuo post implica result.items è annullabile o forse-undefined.
  • Nota quando si utilizza map con un =>-funzione di stile che potrebbe essere necessario avvolgere oggetto-letterali in () così il JS motore non interpretare il { e } come bloccare i delimitatori.
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;
} );

Anche se personalmente mi piacerebbe farlo con un iniziale filter e map seguente procedura:

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 ) );

o ulteriormente semplificato:

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 );

Una soluzione ancora migliore:

  • Se siete in controllo di come il JSON è generato quindi è possibile garantire che alcune (o tutte) le proprietà dell'elemento saranno sempre (e quindi mai undefined o null), quindi se si può garantire che tutte e 3 le proprietà sono sempre insieme (mai null o undefined) e quindi aggiornare l'tipi di interfacce per questo:

    interface ResultItem {
        readonly name       : string;
        readonly createdOn  : string;
        readonly description: string;
    }
    
    • Nota il camelCase proprietà.
    • L'immutabilità di dati è un vantaggio enorme, in modo da assicurarsi che la proprietà di interfaccia sono tutti readonly, tutte le matrici sono readonly T[]e che le proprietà sono solo annotato con ? o | null o | undefined come appropriato, invece di semplicemente supponendo che in un modo o in un altro.
  • Quindi, assicurarsi che si utilizza strictNullChecks nel tsconfig.json o tsc opzioni! - in realtà, basta usare strict sempre!

  • Anche pensare di cambiare la tua JSON DTO dall'utilizzo di un string rappresentazione di una Data (ci sono garanzie circa il fuso orario?) per essere un nativo leggibile Unix timestamp (in millisecondi), in questo modo si possono evitare problemi con Date.parse interamente:

ad esempio:

Risultato.cs:

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

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

Risultato.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 );

...in questo modo si tratta di una singola linea di lavoro.


Il sopra può essere reso ancora più semplice come timestamp Unix sono solo numeri interi che sono direttamente confrontabili, in modo new Date() può essere evitato all'interno del filterin questo modo:

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

Supponendo che si dispone di interfacce definite come questo...

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

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

e si desidera filtrare per gli elementi che sono più vecchi di 90 giorni (esclusi coloro che non CreatedOn), quindi provare questo

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)

Dattiloscritto Giochi Demo

2021-11-24 04:01:43

Perdonate la mia ignoranza (e questa è una bella grande buco di miniera), cosa ({ CreatedOn, ...item }) => ({ fare, esattamente? Non ho mai visto la diffusione operatore ... utilizzato in funzione di un elenco di parametri, al tempo stesso, come un oggetto di valore letterale.
Dai

@Dai estratti di alcune proprietà denominate (CreatedOn) e mantiene il resto in item. Fondamentalmente una scorciatoia per (obj) => { const { a, b, ...rest } = obj; ...
Phil
-1

codice mancante ) di una funzione di 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

La tua risposta non l'indirizzo tsc's tipo di errori.
Dai

Come già scritto, la tua risposta è chiara. Si prega di modifica per aggiungere ulteriori dettagli che aiuteranno gli altri a capire come questo risolve la domanda. Potete trovare ulteriori informazioni su come scrivere le risposte nel centro assistenza.
Community

In altre lingue

Questa pagina è in altre lingue

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