Giter Site home page Giter Site logo

lookup vs as const about variant HOT 7 CLOSED

paarthenon avatar paarthenon commented on May 26, 2024
lookup vs as const

from variant.

Comments (7)

paarthenon avatar paarthenon commented on May 26, 2024 1

so there's the lookup function and the Lookup<T,U = any> type with slightly different answers to this question. The type is essentially the same as creating an object but you restrict the keys so only keys that are a valid key of the variant are allowed. You can also optionally provide a U parameter to restrict the output types, which is very useful if you're expecting someone to pass you that mapping object. I rarely use this type to describe objects I made, I more often use it to constrain function parameters and then use the autocomplete from that constraint when I write my object literal inline.

The lookup function will use that object and return the value of the lookup property for that object's key. I mostly use this to do things like implement tabs or conditional rendering easily.

return (
    <div>
        {lookup(view, {
            Home: <HomeScreen />,
            Registered: <MainView profile={profileInfo} />,
            About: <AboutScreen />,        
        })}
    </div>
)

You could totally use simple object everywhere and as long as you retained the discrete types and it didn't collapse into a (A | B | C | D | E)[] you would be fine.

from variant.

paarthenon avatar paarthenon commented on May 26, 2024 1

based on your Animal example, can we extend them to: type Animal = AnimalWithLegs | AnimalWithWings kind of thing

Yeah totally, though I would do it a different way. Here's my recommendation:

https://github.com/paarthenon/variant#can-i-get-a-real-world-example

I encourage this approach rather than messing with the type aliases directly because values and types exist in different namespaces and for something that bridges the gap between run-time and compile time code you need to exist in both and keep those definitions in sync. Classes do this, which is why you can assign a class name to both a constant and a type, though they technically refer to different things (the constructor function vs. the structure of the generated object). Variant works the same way but I'm not contributing to the language so I can't just make the compiler do the book-keeping.

So in that example, I would do approach it like this

export const Animal = variantList([
    variant('dog', fields<{name: string, favoriteBall?: string}>()),
    variant('cat', fields<{name: string, daysSinceDamage: number}>()),
    variant('snake', (name: string, patternName?: string) => ({
        name,
        pattern: patternName ?? 'striped',
    })),
    variant('pegasus', fields<{color: string, magicType: 'Arcane' | 'Divine'}>()),
    variant('bird'),
]);
export type Animal<T extends TypeNames<typeof Animal> = undefined> = VariantOf<typeof Animal, T>;

export const AnimalWithWings = variantList([
    Animal.bird,
    Animal.pegasus,
]);
export type AnimalWithWings<T extends TypeNames<typeof AnimalWithWings> = undefined> = VariantOf<typeof AnimalWithWings, T>;

export const AnimalWithFourLegs = variantList([
    Animal.cat,
    Animal.dog,
    Animal.pegasus,
]);
export type AnimalWithFourLegs<T extends TypeNames<typeof AnimalWithFourLegs> = undefined> = VariantOf<typeof AnimalWithFourLegs, T>;

You could do it the other way too, create AnimalWithWings and AnimalWithFourLegs and then compose those two together, but in this case pegasis fits both, so it makes more sense to have a single Animal variant that you then divide into categories.

If you do decide to start with the subcategories and then merge them all together that's fine too, but then pegasus might be defined twice (the later definition will win). You can make this a non-issue by storing pegasus as an independent variant.

const pegasus = variant('pegasus', fields<{color: string, magicType: 'Arcane' | 'Divine'}>());

...

export const AnimalWithFourLegs = variantList([
    ...
    pegasus,
]);

...

export const AnimalWithWings = variantList([
    ...
    pegasus,
]);

from variant.

hyusetiawan avatar hyusetiawan commented on May 26, 2024 1

good stuff, thank you for the thorough explanation, I managed to port one part namespaced variants of my project :) I am attempting to port the more nested and more complicated case now.

One follow up question, I see the composition for 2 level categories (Animals, AnimalsWith*) how would you represent N level? for example, AnimalsCanMove?
Using the same method of composition at the Animals level, sounds like there needs to be a repetition (as in listing the same animals in both wings and legs).

Sadly this does not work, (though it would be great if it does, it would make compositions fit naturally with JS syntax):

const AnimalsCanMove = variantList([
   ...AnimalsWithWings,
   ...AnimalsWithLegs,
])

from variant.

hyusetiawan avatar hyusetiawan commented on May 26, 2024

sneaking in one more question,
would love some examples on composability, for example, based on your Animal example, can we extend them to: type Animal = AnimalWithLegs | AnimalWithWings kind of thing

from variant.

paarthenon avatar paarthenon commented on May 26, 2024

Sadly this does not work, (though it would be great if it does, it would make compositions fit naturally with JS syntax):

export const AnimalsCanMove = {
    ...AnimalsWithFourLegs,
    ...AnimalsWithWings,
}

;-)

documentation

variantList consumes an array, but the actual returned value is always an object. You could feed the results into a variantListcall by using Object.values instead, if you like.

export const AnimalsCanMove = variantList([
    ...Object.values(AnimalsWithFourLegs),
    ...Object.values(AnimalsWithWings)
]);

but I tend to use the first syntax. Hey fun fact you can do this too:

export const AnimalsCanMove = {
    ...AnimalsWithFourLegs,
    ...variantList([
        Animal.bird,
        Animal.pegasus,
    ]),
};

go wild.

from variant.

hyusetiawan avatar hyusetiawan commented on May 26, 2024

doh, of course it's just an object in the end :D
again, thank you for the thorough answers :) the typing so far has been much clearer and stricter, as in, no more type: newType as any as SpecificType

from variant.

paarthenon avatar paarthenon commented on May 26, 2024

I'm so glad to hear that. Thanks for opening the first issue.

from variant.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.