Typescript: Operator to cast value into literal

Created on 3 Aug 2018  ·  7Comments  ·  Source: microsoft/TypeScript

As far as I know, something like this does not exist already in Typescript.

I have a situation like this:

const mathBasicSetup = {
    inputs: {
        a: {
            dataType: {
                variant: 'STRING' as 'STRING',
                list: true as true,
                nullable: false as false
            }
        },
        b: {
            dataType: {
                variant: 'NUMBER' as 'NUMBER',
                list: false as false,
                nullable: true as true
            }
        },
    },
    outputs: {
        c: {
            slug: 'c',
            dataType: {
                variant: 'NUMBER' as 'NUMBER',
                list: false as false,
                nullable: false as false
            }
        },
    },
}

I define functions that are hard coded into my application. However I also want to be able to serve them up and their properties for my end users.

So I want to kill two birds in one stone and have type safety and the actual literal set in one variable.

I do this through typeof

export interface OperationBlock<S extends OperationBlockSetup> {
    setup: S;
    func: OperationBlockFunc<S>
}

const mathBasicFunc: OperationBlockFunc<typeof mathBasicSetup> = (inputs) => {
    // my inputs
    // typeof inputs.a = string
    // typeof inputs.b = string
}

In OperationBlockFunc I do this with the inputs

        inputs: { [P in keyof I]:
            I[P]['dataType']['variant'] extends keyof DataTypeVariantsInJS ?
            (
                I[P]['dataType']['nullable'] extends true ? (
                    I[P]['dataType']['list'] extends true ?
                    Array<DataTypeVariantsInJS[I[P]['dataType']['variant']]> | undefined :
                    DataTypeVariantsInJS[I[P]['dataType']['variant']] | undefined
                ) :
.....

...in order to cast the arguments to the correct type.

What I would love is some sort of an operator that would cast values into their literal counterparts.

e.g.

const s = 'mystring'
typeof s: string

const s = 'mystring' as 'mystring' 
typeof s: 'mystring

const s = §'mystring'
typeof s: 'mystring

const b = false
typeof b: boolean

const b = false as false
typeof b: false

const b = §false
typeof b = false

Essentially just a shorthand for foo as foo

Duplicate

All 7 comments

Or perhaps a `literalof´keyword?

Don't know if it's the correct terminology for the ´false´, ´true´ and ´undefined´ etc.. type, though.

You can trivially do this with an own function:

function asLiteral<T extends string | number | boolean>(value: T): T { return value; }

const s = asLiteral('test'); // type: 'test'
const n = asLiteral(54); // type: 54
const b = asLiteral(true); // type: true

Not as nice as compile-time support and adds minimal negligible runtime overhead, but otherwise works fine.

Aha, I see!

Never thought about using a function. Thanks.

I still have some never issues using that, it doesn't seem to exactly slot into a 'foo' as 'foo', even though it seems it should..

I'll have to investigate.

Gotta love metaprogramming ¯_(ツ)_/¯

What would be even better is somehow being able to get the literal result when doing typeof on declared values.

const myObj = { bool: false, string: 'foobar' }

typeof myObj: { bool: boolean, string: string }

"literalof" myObj: { bool: false, string: "foobar" }

You can do the reverse, the "widening", already using conditional types:

type WidenedLiteral<T> =
    T extends string ? string :
    T extends number ? number :
    T extends boolean ? boolean :
    T;

type SW = WidenedLiteral<typeof s>; // Type is string
type NW = WidenedLiteral<typeof n>; // Type is number
type BW = WidenedLiteral<typeof b>; // Type is boolean

And with a mapped type you can change all literal types of an interface to their widened versions.

Duplicate #10195 ?

@RyanCavanaugh Looks like it! I'll close this one.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xealot picture xealot  ·  150Comments

rwyborn picture rwyborn  ·  210Comments

nitzantomer picture nitzantomer  ·  135Comments

yortus picture yortus  ·  157Comments

tenry92 picture tenry92  ·  146Comments