Reputation: 17895
I wrote small function for better handling with types.
function evaluate(variable: any, type: string): any {
switch (type)
{
case 'string': return String(variable);
case 'number': return isNumber(variable) ? Number(variable) : -1;
case 'boolean': {
if (typeof variable === 'boolean')
return variable;
if (typeof variable === 'string')
return (<string>variable).toLowerCase() === 'true';
if (typeof variable === 'number')
return variable !== 0;
return false;
}
default: return null;
}
}
function isNumber(n: any): boolean {
return !isNaN(parseFloat(n)) && isFinite(n);
}
I try same with generics, but don't know how to get type from generic parameter. It´s possible?
Upvotes: 26
Views: 79122
Reputation: 4060
typeof
is a JavaScript operator. It can be used at run time to get the types JavaScript knows about. Generics are a TypeScript concept that helps check the correctness of your code but doesn't exist in the compiled output. So the short answer is no, it's not possible.
But you could do something like this:
class Holder<T> {
value: T;
constructor(value: T) {
this.value = value;
}
typeof(): string {
return typeof this.value;
}
}
This works because I'm operating on the value inside Holder, not on the Holder itself.
Upvotes: 23
Reputation: 3282
You cannot eliminate the type
string, but you can make your function a lot more intelligent and usable in regards to types by adding overloads:
function evaluate(variable: any, type: 'string'): string;
function evaluate(variable: any, type: 'number'): number;
function evaluate(variable: any, type: 'boolean'): boolean;
function evaluate(variable: any, type: string): unknown {
...
default: throw Error('unknown type');
}
const myBool = evaluate('TRUE', 'boolean'); // myBool: boolean
const myNumber = evaluate('91823', 'number'); // myBool: boolean
evaluate('91823', 'qwejrk' as any); // RUNTIME ERROR (violated types)
const mysteryType = 'number' as 'boolean' | 'number';
const myMystery = evaluate('91823', mysteryType); // COMPILER ERROR, no overload matches.
Note that there is no longer a null case, since it is impossible to know if an unknown string
type might actually be containing a valid value like 'number'
at compile-time.
This will be good enough for most people.
However...
Note above that the mysteryType union does not work. If you really really really want that to work for some reason, you can use conditional types instead:
function evaluate<T extends string>(variable: any, type: T):
T extends 'string' ? string :
T extends 'number' ? number :
T extends 'boolean' ? boolean :
never;
function evaluate(variable: any, type: string): unknown {
...
default: throw Error('unknown type');
}
const mysteryType = 'number' as 'boolean' | 'number';
const myMystery = evaluate('91823', mysteryType); // myMystery: number | boolean
T
from MyClass<T>
, that is possible as well:class MyClass<T> {}
type GetMyClassT<C extends MyClass<any>> = C extends MyClass<infer T> ? T : unknown;
const myInstance = new MyClass<"hello">();
let x: GetMyClassT<typeof myInstance>; // x: "hello"
Upvotes: 48