ivanhofer / typesafe-utils

A collection of a few small lightweight typesafe utilities.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Type guard for property

snamiki1212 opened this issue · comments

Hi, thank you for your awesome utils. I'm thinking of using this library because I want to check the property is not undefined but it looks isPropertyNotUndefined only returns boolean without type-guard.

https://github.com/ivanhofer/typesafe-utils/blob/0ecf602c7471d286ee1a9d15182ad1c61157cfb7/src/isUndefined/isUndefined.ts#LL10C1-L10C1

import { isPropertyNotUndefined } from 'typesafe-utils';

const list: Array<{
  lat: number | undefined,
  lng: number | undefined,
}> = [];

const nonTypeSafe = list.filter(item => !!item.lat && !!item.lng);

const typeSafeButNotWorking = list.filter(isPropertyNotUndefined('lat')); // not working
// expect      { lat: number,             lng: number | undefined; }[]
// but type is { lat: number | undefined; lng: number | undefined; }[]

playground1

So, I enhanced isPropertyNotUndefined like following code.

// =====================
// Codes
// =====================
type NonNullableBy<T, K extends keyof T> = {
  [P in keyof T]: P extends K ? NonNullable<T[P]> : T[P];
};

export const isPropertyNotUndefined = <T, K extends keyof T>(
  property: K
) => (obj: T): obj is NonNullableBy<T, K> => obj[property] !== undefined

// =====================
// Examples
// =====================
type Geo = {
  lat: number | undefined,
  lng: number | undefined,
};

const list: Array<Geo> = [];

const nonTypeSafe = list.filter(item => !!item.lat && !!item.lng);

{
  const typeSafe1 = list.filter(isPropertyNotUndefined('lat')); // => NonNullableBy<Geo, "lat">[]
  const {lat, lng} = typeSafe1[0];                              // => lat: number, lng: number | undefined
}

{
  const typeSafe2 = list
    .filter(isPropertyNotUndefined('lat'))
    .filter(isPropertyNotUndefined('lng')); // => NonNullableBy<NonNullableBy<Geo, "lat">, "lng">[]
  const {lat, lng} = typeSafe2[0];          // => lat: number, lng: number
}

playground2

This enhanced code can work with type guard but return type is a bit ugly. I'm not sure arePropertiesNotUndefined will be similarly enhanced.

Do you have any ideas about it? I would create PR If it would be preferred.

Hi @snamiki1212 thanks for looking into this.
I haven't updated the code since a while. A PR would be great to fix the type guard here. I think it is also possible to simplify the type definitions, but I don't have time to take a deeper look into this in the coming weeks as I'm on vacation.

No rush take your nice vacation🏖️