Code Monkey home page Code Monkey logo

Comments (10)

pelotom avatar pelotom commented on August 17, 2024 2

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.

pelotom avatar pelotom commented on August 17, 2024 2

This seems maybe useful enough to add to a utilities module.

from runtypes.

yuhr avatar yuhr commented on August 17, 2024 2

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.

zaverden avatar zaverden commented on August 17, 2024 2

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.

thorning avatar thorning commented on August 17, 2024 1

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.

pelotom avatar pelotom commented on August 17, 2024

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.

danielkcz avatar danielkcz commented on August 17, 2024

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.

thorning avatar thorning commented on August 17, 2024

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.

pelotom avatar pelotom commented on August 17, 2024

@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.

yuhr avatar yuhr commented on August 17, 2024

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)

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.