Comments (7)
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.
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.
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.
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.
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,
}
;-)
variantList
consumes an array, but the actual returned value is always an object. You could feed the results into a variantList
call 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.
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.
I'm so glad to hear that. Thanks for opening the first issue.
from variant.
Related Issues (20)
- Scoped Variants (/namespaces) HOT 3
- Require cycle in generic.ts HOT 2
- custom match creator HOT 8
- Generic variant usage with function as payload HOT 3
- matcher that doesnt require an object HOT 3
- No compiler error from method with variant HOT 4
- Variant 3.0 HOT 32
- Idea: Variation helper type to extract a variant HOT 1
- Exhaustive AND have a default? HOT 4
- Early 2022 Update HOT 1
- Add rx/js examples to documentation
- Expand documentation for the catalog function with integration examples
- Re-explore scoped variants
- A good DX for custom discriminants
- Tree shaking and bundle size
- Move documentation to its own branch
- VariantCreator output hinting for custom discriminants HOT 6
- Shoutout! HOT 2
- `variantModule` export is missing HOT 34
- Change the `type` field HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from variant.