recursion - how to implement typescript deep partial mapped type not breaking array properties -
any ideas how might apply typescript's partial mapped type interface recursively, @ same time not breaking keys array return types?
the following approaches have not been sufficing:
interface user { emailaddress: string; verification: { verified: boolean; verificationcode: string; } activeapps: string[]; } type partialuser = partial<user>; // not affect properties of verification type partialuser2 = deeppartial<user>; // breaks activeapps' array return type; export type deeppartial<t> = { [ p in keyof t ]?: deeppartial<t[ p ]>; }
any ideas?
update: accepted answer - better , more general solve now.
had found temporary workaround involves intersection of types , 2 mapped types follows. notable drawback have supply property overrides restore sullied keys, ones array return types.
e.g.
type partialdeep<t> = { [ p in keyof t ]?: partialdeep<t[ p ]>; } type partialrestorearrays<k> = { [ p in keyof k ]?: k[ p ]; } export type deeppartial<t, k> = partialdeep<t> & partialrestorearrays<k>; interface user { emailaddress: string; verification: { verified: boolean; verificationcode: string; } activeapps: string[]; } export type adddetailspartialed = deeppartial<user, { activeapps?: string[]; }>
okay, here best attempt @ crazy general solution (requiring typescript 2.4 , up) might not worth you, if want use it, guest:
first, need type-level boolean logic:
type false = '0' type true = '1' type bool = false | true type ifelse<cond extends bool, then, else> = {'0': else; '1': then;}[cond];
all need know here type ifelse<true,a,b>
evaluates a
, ifelse<false,a,b>
evaluates b
.
now define record type rec<k,v,x>
, object key k
, value type v
, rec<k,v,true>
means property required, , rec<k,v,false>
means property optional:
type rec<k extends string, v, required extends bool> = ifelse<required, record<k, v>, partial<record<k, v>>>
at point can user
, deeppartialuser
types. let's describe general userschema<r>
every property care either required or optional, depending on whether r
true
or false
:
type userschema<r extends bool> = rec<'emailaddress', string, r> & rec<'verification', ( rec<'verified', boolean, r> & rec<'verificationcode', string, r> ), r> & rec<'activeapps', string[], r>
ugly, right? can describe both user
, deeppartialuser
as:
interface user extends userschema<true> { } // required interface deeppartialuser extends userschema<false> { } // optional
and see in action:
var user: user = { emailaddress: 'foo@example.com', verification: { verified: true, verificationcode: 'shazam' }, activeapps: ['netflix','facebook','angrybirds'] } // missing properties or cause error var deeppartialuser: deeppartialuser = { emailaddress: 'bar@example.com', verification: { verified: false } } // missing properties fine, still error
there go. hope helps!
Comments
Post a Comment