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