You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Suppose we want to provide a function that extracts values from an object by keys with a type guard, for example:
import{assertEquals,assertThrows}from"jsr:@std/assert";import{assertType,Has}from"jsr:@std/testing/types";Deno.test("extract",()=>{// Users can define their own extract functionconstextractDate=(value: unknown)=>extract(value,["day","month"],(value: unknown): value is number=>typeofvalue==="number",);constmatched=extractDate({day: 21,month: 4,location: "Tokyo"});assertType<Has<typeofmatched,number[]>>(true);assertEquals(matched,[21,4]);assertThrows(()=>extractDate({day: 21,location: "Osaka"}));});
I find the library makes me implement this kind of function quite elegantly:
import{match,placeholderas_,}from"jsr:@core/[email protected]";import{associateWith}from"jsr:@std/collections/associate-with";functionextract<Vextendsunknown>(from: unknown,// expected to extend Record<string, V>by: string[],guard: (value: unknown)=>value is V,// type guard for each entry): V[]{constpattern=associateWith(by,(it)=>_(it,guard));// => Record<string, RegularPlaceholder<string, (value: unknown) => value is V>>constresult=match(pattern,from);// => undefinedif(!result){thrownewTypeError(`Could not extract expected values from ${from}.`);}returnby.map((key)=>result[key]));// => never[]}
This code runs as expected and passes the test. But the problem here is that the type of result is inferred as undefined, which does not seem consistent with the actual behavior.
We can improve this a bit by binding the type of by to a type parameter:
import{match,placeholderas_,RegularPlaceholder,}from"jsr:@core/[email protected]";import{associateWith}from"jsr:@std/collections/associate-with";functionextract<Kextendsstring,Vextendsunknown>(from: unknown,// expected to extend Record<K, V>by: K[],guard: (value: unknown)=>value is V,// type guard for each entry): V[]{constpattern=associateWith(by,(it)=>_(it,guard),)as{[LinK]: RegularPlaceholder<L,(value: unknown)=>value is V>};constresult=match(pattern,from);// => Match<{ [L in K]: RegularPlaceholder<L, (value: unknown) => value is V>; }> | undefinedif(result===undefined){thrownewTypeError(`Could not extract expected values from ${from}.`);}returnby.map((key)=>result[key]);// => Type 'Match<{ [L in K]: RegularPlaceholder<L, (value: unknown) => value is V>; }>[K][]' is not assignable to type 'V[]'.}
This code also passes the test. Now the type of result is inferred to be non-nullable, but still does not allow further operations on it.
I would like to see the type of result more "expected", like Record<string, V> | undefined in the first implementation, and Record<K, V> | undefined in the second one.
I'm totally not sure if this is a justified request in terms of the original concept of the library, but I don't beleive it a bad idea to share what I experimented with you here 😃
The text was updated successfully, but these errors were encountered:
Now the type of result in the first implementation is inferred as non-nullable;
functionextract<Vextendsunknown>(from: unknown,// expected to extend Record<string, V>by: string[],guard: (value: unknown)=>value is V,// type guard for each entry): V[]{constpattern=associateWith(by,(it)=>_(it,guard));// => Record<string, RegularPlaceholder<string, (value: unknown) => value is V>>constresult=match(pattern,from);// => Record<Key, unknown> | undefinedif(!result){thrownewTypeError(`Could not extract expected values from ${from}.`);}returnby.map((key)=>result[key]);// => unknown[]}
Suppose we want to provide a function that extracts values from an object by keys with a type guard, for example:
I find the library makes me implement this kind of function quite elegantly:
This code runs as expected and passes the test. But the problem here is that the type of
result
is inferred asundefined
, which does not seem consistent with the actual behavior.We can improve this a bit by binding the type of
by
to a type parameter:This code also passes the test. Now the type of
result
is inferred to be non-nullable, but still does not allow further operations on it.I would like to see the type of
result
more "expected", likeRecord<string, V> | undefined
in the first implementation, andRecord<K, V> | undefined
in the second one.I'm totally not sure if this is a justified request in terms of the original concept of the library, but I don't beleive it a bad idea to share what I experimented with you here 😃
The text was updated successfully, but these errors were encountered: