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?
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: ""})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With