How should I force TypeScript to understand that there won't be any null in this array?

Viewed 190

I'm coming from JavaScript and learning TypeScript. I'm used to filter null from an array by using .filter(x => x), however, with TypeScript it asks me to define that the array can contain null, which isn't true because filter removes all null from the array:

interface ILabels {
    alias: string
    publicKey: string
    lat: number
    long: number
}

const labels: ILabels[] = data.map((d) => {
  if (d.lat && d.long) {
    return {
      alias: d.alias || d.publicKey,
      publicKey: d.publicKey,
      lat: d.lat,
      long: d.long,
    };
  }
  return null;
}).filter((x) => x);

How should I force TypeScript to understand that there won't be any null in this array? The error TypeScript gives me is:

TS2322: Type '({ alias: string; publicKey: string; lat: number; long: number; } | null)[]' is not assignable to type 'ILabels[]'.   Type '{ alias: string; publicKey: string; lat: number; long: number; } | null' is not assignable to type 'ILabels'.     Type 'null' is not assignable to type 'ILabels'.

1 Answers

One way is to use a user-defined type guard:

function nonNull<T>(val: T | null): val is T {
  return val !== null;
}

const labels: ILabels[] = data.map((d) => {
  if (d.lat && d.long) {
    return {
      alias: d.alias || d.publicKey,
      publicKey: d.publicKey,
      lat: d.lat,
      long: d.long,
    };
  }
  return null;
}).filter(nonNull);

Or, with an arrow function:

const labels: ILabels[] = data.map((d) => {
  if (d.lat && d.long) {
    return {
      alias: d.alias || d.publicKey,
      publicKey: d.publicKey,
      lat: d.lat,
      long: d.long,
    };
  }
  return null;
}).filter(<T,>(x: T | null): x is T => x !== null);
Related