Comments (10)
Yea, I already figured that out, but it feels kinda dirty to repeat this all over the place (and abusing some internals) :)
It's not an abuse of internals, those methods are part of the public API. I agree it's not ideal to have to repeat it everywhere; fortunately you can define a function which abstracts this logic:
import { LiteralBase } from 'runtypes/types/literal';
function enumeration<T extends LiteralBase>(union: { alternatives: Literal<T>[] }): T[] {
return union.alternatives.map(literal => literal.value);
}
Then you can use it like so:
const State = Union(
Literal('Unknown'),
Literal('Online'),
Literal('Offline')
)
const stateLiterals = enumeration(State)
// stateLiterals: ("Unknown" | "Online" | "Offline")[]
from runtypes.
This seems maybe useful enough to add to a utilities module.
from runtypes.
I've tested on current master
with #166 merged, and noticed it won't work out of the box. We still need some ugly workaround like following:
const values = ['Unknown', 'Online', 'Offline'] as const;
type ElementOf<T extends readonly unknown[]> = T extends readonly (infer E)[] ? E : never;
type LiteralOf<T extends readonly unknown[]> = {
[K in keyof T]: T[K] extends ElementOf<T>
? T[K] extends LiteralBase
? Literal<T[K]>
: never
: never;
};
type L = LiteralOf<typeof values>;
const literals = (values.map(Literal) as unknown) as L;
const Values = Union(...literals);
type Values = Static<typeof Values>;
const v: Values = 'Online';
expect(() => Values.check(v)).not.toThrow();
So it seems to worth providing some utilities for this...
from runtypes.
Maybe this util function will help for the case:
import * as R from "runtypes";
import { LiteralBase } from "runtypes/lib/types/literal";
type Tuple<T> = [T, ...T[]];
type Literals<T extends Tuple<LiteralBase>> = {
[K in keyof T]: T[K] extends LiteralBase ? R.Literal<T[K]> : never;
};
interface LiteralsUnion<T extends Tuple<LiteralBase>> extends R.Union<[...Literals<T>]> {
getOptions(): T;
}
export function LiteralsUnion<T extends Tuple<LiteralBase>>(...values: T): LiteralsUnion<T> {
const literals = values.map((v) => R.Literal(v)) as Literals<T>;
return Object.assign(R.Union(...literals), {
getOptions: () => values,
});
}
Usage:
export const WeekDays = LiteralsUnion("mo", "tu", "we", "th", "fr", "sa", "su");
export type WeekDays = Static<typeof WeekDays>;
// ^^^^^^WeekDays = "mo" | "tu" | "we" | "th" | "fr" | "sa" | "su"
const wd = WeekDays.getOptions();
// ^^^wd: ["mo", "tu", "we", "th", "fr", "sa", "su"]
I find it extreamly helpful.
@yuhr what do you think, should we have LiteralsUnion
in core? I can make a PR with tests if you think it fits
from runtypes.
If I have some extra time I'll look at it. Especially if we end up using the library.
It seems the tuple spread comming in TS 3.0 microsoft/TypeScript#24897 will be a great help here (and also in the Union type)
from runtypes.
If I understand correctly, you just want to extract an array of the literal values?
const stateLiterals = State.alternatives.map(literal => literal.value)
// stateLiterals: ("Unknown" | "Online" | "Offline")[]
from runtypes.
Yea, I already figured that out, but it feels kinda dirty to repeat this all over the place (and abusing some internals) :)
Perhaps it might be even useful to introduce some helper function here to create string literal union from an array? I don't see that far into Typescript so I am not sure if it's possible.
const StateEnum = ['Unknown', 'Online', 'Offline']
const State = LiteralUnion(StateEnum)
...
connState: types.enumeration(StateEnum)
from runtypes.
I found this library from my search for this feature. It seems as my first glance that a LiteralUnion('one','two','three'
type might be worthy addition, I use it this kind of union a lot in place of string enums and think it is a fairly common pattern.
It will pretty much be an extension of
Union(
Literal('one'),
Literal('two'),
Literal('three')
)
with a convenient constructor, and helper methods to i.e. get a runtime tuple with each possible value
from runtypes.
@thorning yeah, I agree, it's probably useful enough to add to the core library. Or, following mobx-state-tree
's example, it could be called Enumeration
. I'd definitely entertain a PR if you'd like to add it!
from runtypes.
I think the correct way to achieve this will be:
const values = ['Unknown', 'Online', 'Offline'] as const
const Values = Union(...values.map(Literal))
But this is not possible for now, because the current implementation of Union
does not allow arbitrary length arguments. Probably #166 will resolve this.
from runtypes.
Related Issues (20)
- Is there a way to omit everything that's not defined by the Record instance? HOT 1
- Create runtypes from existing TypeScript types? HOT 1
- Printable form of type from runtype? HOT 1
- Unuseful error message on typechecking HOT 1
- Cannot validate optional+null circulare fields HOT 4
- Optional types in Tuple HOT 1
- How check for ObjectId? HOT 3
- Function which accepts a runtype and omits some fields HOT 1
- `omit` properties of a `Constraint` or `Intersect`? HOT 2
- Constraint::reflect does not expose .underlying
- Support for Set type HOT 2
- [Feature Request] Type Guard for ValidationError HOT 2
- Option to return errors instead of throwing them for performant validation. HOT 4
- Runtypes-like `.guard()` HOT 1
- How do I exclude undefined properties from record? HOT 2
- Is it possible to have more than one brand HOT 2
- Type validated by Dictionary is different than returned type
- How do I define an array which is optional yet in case it was defined it shouldn't be empty ? HOT 2
- Performance
- Publish to deno.land/x HOT 4
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 runtypes.