[ReadOnlyArray] Array.isEmptyArray does not perform type narrowing
Given a variable arr of type T[], I'm noticing that
import * as Array from "@effect/data/ReadonlyArray"
if(Array.isEmptyArray(arr)) {
return;
}
arr; // <-- here arr still has type T[]
whereas
import * as Array from "@effect/data/ReadonlyArray"
if(!Array.isNonEmptyArray(arr)) {
return;
}
arr; // <-- here arr has type [T, ...T[]]
Am I missing something? Shouldn't the first snippet also exhibit the same behavior, i.e. narrow the type down to a non-empty array?
This is a TypeScript issue AFAIK. Refinement types are good at telling what a type is, but not good at what it isn't, unless the type you're refinining is a union. However, in this example, we're dealing subtypes of Arrays rather than unions.
EDIT: For example, we have similar kinds of code at my job:
You can get the desired type safety at a cost of double negation (which I wouldn't trade for)
import { isNonEmptyArray } from '@effect/data/ReadonlyArray'
function foo<T>(arr: T[]) {
if (!isNonEmptyArray(arr)) {
return;
}
arr; // [T, ...T[]]
}
Or if you can live with nesting
import { isNonEmptyArray } from '@effect/data/ReadonlyArray'
function foo<T>(arr: T[]) {
if (isNonEmptyArray(arr)) {
arr; // [T, ...T[]]
}
}
Unfortunately we can't fix this, as typescript only allows you to narrow based on what the type is, not what it isn't. Will close for now.