Open Kinrany opened 5 years ago
Hey, thanks for the question!
does this snippet work?
import { Union, of, GenericValType } from 'ts-union'
const LoadingEnum = Union(T => ({
Loading: of(null),
Loaded: of(T)
}));
type LoadingEnum<T> = GenericValType<T, typeof LoadingEnum.T>;
It does, thanks!
Next question: how do I get the type of a payload of a variant of a generic union?
// `Cow` is `{cow: 'cow'}`
type Cow = ???<LoadingEnum<{cow: 'cow'}>, 'Loaded'>;
Maybe im missing something but why not:
type Cow = {cow: 'cow'};
basically if you have a snippet like:
const Maybe = Union( a=> ({
Just: of(a),
Nothing: of(null)
}))
type Maybe<T> = GenericValType<T, typeof Maybe.T>
const printIfExists = <T>(maybe: Maybe<T> ) => {...}
You essentially want to extract T
type from it. Is there a situation when you don't know T
?
If so could you give a little bit more context around your question?
Yeah, I don't know T
. More accurately, it's defined in another module, and I don't want to depend on it. I was trying to use the new enum type to rewrite an equivalent of MaybeLoaded['Loaded']
.
// maybe.ts
export const Maybe<T> = ...
export type Maybe<T> = ...
// thing.ts
export type Thing = ...
// maybeThing.ts
import {Maybe} from './maybe';
import {Thing} from './thing';
export type MaybeThing = Maybe<Thing>;
// doStuff.ts
import {MaybeThing} from './maybeThing';
export function doStuff(maybeThings: MaybeThing[]) {
const things: PayloadOf<MaybeThing, 'Just'>[] = /* filter actual things */
}
It does look like a weird problem to have, but unfortunately it's not something I can easily change.
Ok. In that particular case you want to extract back the type of the generic union given the existing one. Let me try to brainstorm:
type ExtractThing<T> = T extends Maybe<infer Thing>? Thing: never;
type Payload = ExtractThing<MaybeThing> ;
I think it will work
Oh, right. This should work, thanks again :D
Wait, what if it's not a generic type, or a generic type that uses the type argument in a different way?
Could you give me examples? :)
const MaybePair = Union(T => ({
None: of(null),
Some: of<typeof T, typeof T>()
})
type MaybePair<T> = ...
type MaybePairOfThings = MaybePair<Thing>;
type PairOfThings = /* an equivalent of MaybePairOfThings['Some'] */
That is currently not supported :( It is definitely doable but would require a lot of typescript magic.
Oh well.
A tangentially related idea: what if there was a Variant<TTag, TValue>
type, and the Union
function merely returned a dictionary of functions that returned Variants? Like a structural analogue to the nominal sum types in other languages.
It'd be possible to solve the problem above with just T extends Variant<'Some', infer TValue> ? TValue : never
.
Full disclosure: I've already tried to implement this, but types are hard. Now I'm hoping that someone will solve it before I have to try again out of frustration :P
If you have a sketch of this that is backward compatible with the current api im interested in exploring that
Also curios do you have an actual usecase for having a generic pair?
Also curios do you have an actual usecase for having a generic pair?
I'm not entirely sure it's a good case, but I was trying to reimplement a function withLoading
that converts an arbitrary React-like render function (args: T) => Node
into an equivalent of (args: {loading: undefined} | {loaded: T}) => Node
.
I'm submitting a ... [ ] bug report [ ] feature request [ ] question about the decisions made in the repository [x] question about how to use this project
Summary
How do I create an equivalent of this Rust type, including an interface for all of it's members?