#Transforming object to class instance while preserving the types

60 messages · Page 1 of 1 (latest)

icy totem
#

Hi! I've got a code where I have defined class Opt<T> {...} and class Group<...> { ... }. Group contains other Groups and Opts. I also have a plain object that does not use these classes and I want to convert it to instances of these classes while preserving types.

I know that code is worth more than 1000 words, so here is the example - I want to write a function which transforms input to output. The body of the function does not matter, I have trouble with expressing the type signature. Is it somehow possible?

https://www.typescriptlang.org/play?ssl=23&ssc=1&pln=23&pc=12#code/MYGwhgzhAEDyAOAXAPAFQHzQN4Chr+gBMBTAMzAFcREAuaVPAkiYAJwEsl2B7AOzoiIOvAOaN8wPoNYVgibqwAUwUiLq4CmomUrU6DLU2IsOXPgKHtR46AF8AlNhubEAC3YQAdCXJVE0AF5oFRFvHT9nAjcPMJNORB5eQODVWLZ4xJtbHGycRABPeGI4M14ANTAQCmKg6SsRaAAfaAAjbm4QYjAk5t4KAFsW4lYm6DrRAG0AXTzC4oBBXnyEBL5kleQVxIqq4nRZopLV3ggAJWJJVkJk88vCZHGRABpoReXS-YLDgHFWbgp4GcLgprkFbiCHpZRC83r9-vB9jgrIhhuRgAslnCAU5NNxShA6FspOCrjYRH8AQToFjASTCDkcDhQJAYDTNvjoMQAB4o3iEGBEk50l40mDc3n86kU2nAq6YDQEPHHKmCmBBLC2aCQI6JCBk6VU0XJDVa1kGmySE5CWTyJQhAD86mgSt1jp1UgA3NByfCIG6jQ4cYZglJ-C6pMkHZ5wydIvh2KRoIoYzAAIRBPogECOBXBqLuLwp5IpuN2UuWwTeg2R1T2zw+ymlhNJhuA6Dp6CZ7NBvP4aJeVtqqu+0vZTTZXJM0PQKzwCj+dX633qUsiACMK97ivxm63WhjG57e8MPl0tGgAFYnqXj8x0qU6AByA-aOKlR834O2a-H3GlABMu6-lop5+HQABsP7ASBxj3scT4xv+r5wYkH7QWWx7fp++CDkBv7rgA+uueHoSmJHoduxwAMzkRRMG+Ho0AAOxQXReZ3qY8HQM+pRUchnGodhv5jmxInAWJvYSeOWQMlOVrOvOc4Lp2xAAO5SvCii5sOlK0d6h68GpGkAlpQlkUex4HnQhnqSsplsdoDHnleQnsbBAnmNxL4cRkfBodBDisb+iHWUZdnaehoGMZBrnBj5D5eQB-G+bw-nifYQlYceuEWXuhHESp6k0vZbHmRFpW8aFtlICVDknuEjEsbFwHxVxPHUcl77NZJGUOVJe4OJlo69QQE72EAA

slim thunderBOT
#

@icy totem Here's a shortened URL of your playground link! You can remove the full link from your message.

wdanilo#2781

Preview:ts ... class Group< Options extends OptionsRecord ...

icy totem
#

Also, to explain why I need it. I want to store the config in json file and load it to both JS and Rust code.

polar spade
#

i don't believe this is possible

icy totem
#

@polar spade oh actually I am able to import json and get it properly typed in TS

polar spade
#

oh?!!!

#

!:narrow

slim thunderBOT
#
T6#2591

Preview:ts type _Narrow<T, U> = [U] extends [T] ? U : Extract<T, U> type Narrow<T = unknown> = | _Narrow<T, 0 | number & {}> | _Narrow<T, 0n | bigint & {}> | _Narrow<T, "" | string & {}> | _Narrow<T, boolean> | _Narrow<T, symbol> | _Narrow<T, []> | _Narrow<T, { [_: PropertyKey]: Narrow }> | (T extends object ? { [K in keyof T]: Narrow<T[K]> } : never) | Extract<{} | null | undefined, T> ...

icy totem
#

import * as myjson from './file.json' works

polar spade
#

?!!!

#

oh

#

you don't need the actual names at the type level

#

just a heads up though

icy totem
#

no, it just works. And all the nested fields are typed correctly

polar spade
#

but is default typed as 5

icy totem
#

no, as number

#

and thats enough for me

polar spade
icy totem
#

oh, gotcha. Anyway, this is enough of type info for me. Do you think it is possible. to transform the types as I want then ?

polar spade
#

i'm guessing you want to be able to access methods on Opt and Group?

icy totem
#

thats right

polar spade
#

uhh

#

note that you don't have the javascript code to turn the options and groups into objects

#

so you'd have to implement that later

icy totem
#

sure, but thats simple

slim thunderBOT
#
n_n#2622

Preview:```ts
...
class Group<
Options extends
| OptionsRecord
| undefined = undefined,
Groups extends GroupsRecord | undefined = undefined

{
options = {} as {
[K in keyof Options]: Opt<
NonNullable<Options>[K]["default"]

}
groups = {} as {
[K in keyof Groups]: Group<
NonNullable<Groups>[K]["options"],
NonNullable<
...```

polar spade
#

yup

#

so

#

something liek this should work

#

if that's maintainable enough

icy totem
#

Hmm, it doesnt 😦

#

Here, option1 is not typed as Opt<...> .

#

Anyway, this does not have to be done via constructor, it can be just a function convert that converts between these two things

#

I mean, a function convert(input) that would return output

polar spade
#

check the code at the bottom

icy totem
#

ohhh, interesting, hmmm, I dont understand why, brb, trying to parse / understand it

polar spade
#

it does a transformation on the type parameters

icy totem
#

this is so tricky!

polar spade
#

(see the types of options and groups)

polar spade
# icy totem this is so tricky!

yeah! not sure if there's a nicer way to do it... but i wouldn't be too sure, because you do have to change the type to the class at some point

#

also note that typescript may not be smart enough to infer the types of this.options = correctly even after you have a correct implementation

#

and so you may need to leave the unsafe type assertions there

icy totem
#

This has onl yone problem. ... output2 type still does not mention Opt, it mentions only plain object strcutre. I understand it works, because we are making type transformation in the field, but I also have afuntion merge which merges 2 groups together, like:

merge<Other extends AnyGroup>(other?: Other | null): this & Other {...}

^^^ This is a method in group. Which woild not work if Id try to merge a group created from a plain object and a hand-written one, right ?

polar spade
#

nah it would

#

well actually

#

hmm

#

well remember (or note that?) in typescript, it's only the shape that matters

#

TS doesn't care about generic parameters, it cares about whether options is the right type

#

add to that the fact that AnyGroup actually accepts even the plain object...

icy totem
#

damn, it works

#

ok, its a type system that I am completely not used to

#

thank you so so so so much @polar spade ❤️

#

Ehh, how I could pay you back for all your help? 😦

polar spade
#

i uhhh

#

honestly, going through the effort of making a playground and making it easy to help is more than enough tbh

#

anyway...

#

!close