Nested `?` doesn't narrow
devanshj opened this issue · 3 comments
import { p, pa } from "@sthir/predicate"
declare let x: { a: { b: string } | undefined }
if (pa(x, p(".a?.b"))) {
x.a.b // should compile, doesn't
}
Originally posted by @VinSpee in #1 (comment)
here's a minimal repro:
import { p } from "@sthir/predicate";
interface Image {
height: number;
width: number;
url: string;
name: string;
}
interface Variants {
"square-small2x": Image;
"square-small": Image;
"landscape-crop": Image;
"landscape-crop2x": Image;
}
export type Profile = {
id: string;
images: Variants | null | undefined;
displayName: string;
jobTitle: string;
};
const data: Profile[] = [
{
id: "618c4a28-925c-42df-a655-30552ea53607",
images: {
"square-small2x": {
height: 480,
width: 480,
url: "https://avatars.dicebear.com/api/adventurer-neutral/ts.svg",
name: "square-small2x",
},
"square-small": {
height: 240,
width: 240,
url: "https://avatars.dicebear.com/api/adventurer-neutral/ts.svg",
name: "square-small",
},
"landscape-crop": {
height: 267,
width: 400,
url: "https://avatars.dicebear.com/api/adventurer-neutral/ts.svg",
name: "landscape-crop",
},
"landscape-crop2x": {
height: 533,
width: 800,
url: "https://avatars.dicebear.com/api/adventurer-neutral/ts.svg",
name: "landscape-crop2x",
},
},
displayName: "Jennifer Smith",
jobTitle: "Marketing Executive",
},
];
data.filter(p("?.images?.square-small2x"));
Expression produces a union type that is too complex to represent.
Argument of type '["?.images?.square-small2x"]' is not assignable to parameter of type '[] | [Comparator] | [Operator]'.
Type '["?.images?.square-small2x"]' is not assignable to type '[Comparator]'.
Type '"?.images?.square-small2x"' is not assignable to type 'Comparator'.
@VinSpee The error is correct that you don't need the leading ?
because profile
is always defined. The problem is this should compile but it doesn't...
// https://tsplay.dev/NrG7zm
data.filter(p(".images?.square-small2x")).map(profile => profile.images["square-small2x"]);
A more minimal repro is this...
import { p, pa } from "@sthir/predicate"
declare let x: { a: { b: string } | undefined }
if (pa(x, p(".a?.b"))) {
x.a.b // should compile, doesn't
}
Will look into this soon!
Also in meantime you can use this instead...
// https://tsplay.dev/mMVZbW
let urls: string[] =
data
.filter(p(".images?.square-small2x typeof ===", "object"))
.map(profile => profile.images["square-small2x"].url); // compiles
Fixed it, now the following compiles. I hope that solves your issue.
let urls: string[] =
data
.filter(p(".images?.square-small2x"))
.map(profile => profile.images["square-small2x"].url);
The playground still picks v0.0.8
instead of latest v0.0.9
because of cache, but you can try it locally.
Thanks again for reporting and giving @sthir/predicate
a try!