Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type guards checking for property existence

Tags:

typescript

I know type guards can be used to distinguish between unioned types. But is it possible to detect property existence on an unknown type being passed in?

This code does not work.

function foo(bar: unknown | { createdDate: Date }) {
    if (bar.createdDate)
        alert(bar.createdDate); //Doesn't work
}

Neither does this:

function foo(bar: unknown | { createdDate: Date }) {
    if ('createdDate' in bar)
        alert(bar.createdDate); //Doesn't work
}

Note: Changing the type of bar to any does work, but the compiler is not narrowing the type inside the if statement. It is typing bar.createdDate as any.

I've also tried generic versions of this function to avail.

function foo<T extends (unknown | { createdDate: Date })>(bar: T) {
    if ('createdDate' in bar)
        alert(bar.createdDate); //Doesn't work
}

Is there a way to confirm existence of a property on an unknown type and then have the compiler narrow the type appropriately?

like image 797
MgSam Avatar asked Dec 07 '25 03:12

MgSam


1 Answers

In a union unknown "eats up" any other members, so unknown | { createdDate: Date } == unknown (this behavior is described in the PR)

Also from the PR, unknown can be narrowed in the following ways:

function f20(x: unknown) {
    if (typeof x === "string" || typeof x === "number") {
        x;  // string | number
    }
    if (x instanceof Error) {
        x;  // Error
    }
    if (isFunction(x)) {
        x;  // Function
    }
}

It would appear the only way to achieve the outcome you want is using a custom type guard (since typeof x === "typename" is not applicable andinstanceof` does not work with interfaces)

function foo(bar: unknown) {
  const hasCreatedDate = (u: any): u is { createdDate: Date } => "createdDate" in u;
  if (hasCreatedDate(bar)) {
    alert(bar.createdDate);
  }
}

Or you can use Object which will not eat up any other union members

function foo(bar: Object | { createdDate: Date }) {
  if ("createdDate" in bar) {
    alert(bar.createdDate); 
  }
}

foo({aa: ""})
like image 65
Titian Cernicova-Dragomir Avatar answered Dec 08 '25 18:12

Titian Cernicova-Dragomir