The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
#How to filter items in a const assertion with Array attributes
32 messages · Page 1 of 1 (latest)
I want to filter based on the presence of any of the possible attr and get only the matching ones.
I can do it with a non-array field, say attr2: "A", attr2: "B" then I could find all B and all A but the same doesn't work for some value in the readonly array
Eh, not sure what the goal of this code is, are you trying to use y to check something about d, or the opposite?
Because there's this:
!:includes
`!retsam19:includes`:
The type of Array.prototype.includes assumes that you're using the string to check something about the array. If you're trying to do the reverse, a modified type signature is useful:
function includes<S extends string>(haystack: readonly S[], needle: string): needle is S {
const _haystack: readonly string[] = haystack;
return _haystack.includes(needle)
}
declare const x: string;
if(includes(["a", "b", "c"], x)) {
// x is "a" | "b" | "c"
}
BTW, @short owl you don't need a link shortener, just send the full URL as its own message and the bot handles it
Preview:```ts
const data = [
{
attr: ["A", "B", "C", "D"],
},
{
attr: ["D", "E", "F"],
},
] as const
type Data = typeof data[number]
type Y = "A" | "B" | "C"
function hasY(y: Y, d: Data) {
return d.attr.includes(y)
}```
You can choose specific lines to embed by selecting them before copying the link.
Yes I'm using Y to check if D has the needed value in the attr array.
I want to map the data to something like dataWithAttrD = filterDataHasAttrD(data) and type it such that type hasAttrD has all entries that contain an attr: ["D"] and anything else.
Similar to if the object had an attribute isLike: "A" | "B" | "C" and I wanted to filter them I'd use:
function isLike<T extends IsLike = IsLike>(isLike: T) {
return <D extends Data>(data: D): data is D & {isLike: T} => data.isLike === isLike;
}
That's a predicate that I could use to filter data.
type IsLikePredicate<T extends IsLike> = ReturnType<typeof isLike<T>>;
const isLikeA = isLike("A");
function filterDataByIsLike<U extends IsLike>(filter: IsLikePredicate<U>) {
return data.filter(d => filter(d));
}
In the playground link, for some reason it types includes as ReadonlyArray<T>.includes(searchElement: "D", fromIndex?: number | undefined): boolean
Preview:```ts
type Data = { readonly attr: readonly unknown[] }
type ExtractAttr<T extends Data, A> = T extends T
? A extends T['attr'][number]
? T
: never
: never
function hasAttr<T extends Data, const A extends T['attr'][number]>(
data: T,
...```
You can choose specific lines to embed by selecting them before copying the link.
So it seems like the key is type Data = { readonly attr: readonly unknown[] }
Wondering if I can make this type based on the const itself.
I mean you can.
You can replace type Data = typeof data and it will still work, although you would need to fix it to .includes(attr as never).
But I personally don't think it's necessary, this version works with any kind of data with attr.
Yea, I mean I might filter on attr: or have other fields (that might be of different types) to filter on.
includes(attr as never) is actually better than what I had which was (d.attr as string[]).includes(y)
Yeah, as never is a convenient hack, but you need to make sure it's correct because it's unsafe just like any other usage of as.
The noteworthy part of the code I've given is just the type guard narrowing, see how data is narrowed in each if depending on the attr you pass in. If you don't need that, then yeah as never will just fix your original issue.
I do need the narrowing of the type, that's kinda the requirement.
It still works with this:
Preview:```ts
//type Data = { readonly attr: readonly unknown[] }
type Data = typeof datas[number];
type ExtractAttr<T extends Data, A> = T extends T
? A extends T['attr'][number]
? T
: never
: never
function hasAttr<T extends Data, const A extends T['attr'][number]>(
...```
You can choose specific lines to embed by selecting them before copying the link.
It seems better than as any but I'm not sure it is.
as never is just a slightly safer as any.
Let me know if I should create a new post for this, but to put this into perspective, this is what I'm doing:
Preview:ts const data = [ { key: "X", attr: ["A", "B", "C", "D"], state: "Good", }, { key: "Y", attr: ["D", "E", "F"], state: "Bad", }, { key: "Z", attr: ["D", "A", "B"], state: "Bad", }, ] as const type Data = typeof data[number] ...
You can choose specific lines to embed by selecting them before copying the link.
Now you can see I'm re-mapping the const data into different forms (feel free to tell me if I'm doing something wrong in there). Filtering on state works, I'm not looking to filter on attr as well.