i have function that can get multiple types as argumet (in my case "get" proxy handler) and that argumet should be processed diferently depends on its type.
for plain js i know how to deal with it, something like this:
const calls = {
"String": (str)=>{/*...*/},
"Number": (num)=>{/*...*/},
"Symbol": (symb)=>{/*...*/},
"Object": (obj)=>{/*...*/}
}
function foo(obj){
const name = Object.getPrototypeOf(obj).constructor.name;
if (name in calls) {
calls[name](obj);
} else {
/*unknow type*/
}
}
but in typescript in terms to keep type track, all that comes to mind is is type guards
// isNumber, isString, isSymbol, isObject - type guards
function foo(obj: string | number | symbol):void {
if (isString(obj)){
/*...*/
} else if (isNumber(obj)) {
/*...*/
} else if (isSymbol(obj)) {
/*...*/
} else if (isObject(obj)) {
/*...*/
} else {
/*unknow type*/
}
}
but in compare with plain js its look silly (will fast grow out of control and also make alot of unnecessary operations), so:
is there any equivalent solutions for TS?
example 2.0:
class Container {
constructor(){}
metaData = {};
props = new Map();
}
const valuePreProcess = {
"Number"(target, prop, value){ return value.toString() },
"Container"(target, prop, value){ value.metadata.parent = target; return value; }
}
const handlers = {
set(target, prop, value){
//define type or may be inner class of passed 'value' to process it right
const processedValue = valuePreProcess[<typeOfValue>](target, prop, value);
target.props.set(prop, processedValue);
}
}
const obj = new Proxy(new Container(),handlers);
probably use prototype itself as key
const valuePreProcessors = new Map([
[Number.prototype,(target, prop, value)=>value.toString()],
[Container.prototype,(target, prop, value)=>{ value.metadata.parent = target; return value; }]
]);
const handlers = {
set(target, prop, value){
const processFunc = valuePreProcessors.get(Object.getPrototypeOf(value));
target.props.set(prop, processFunc(target, prop, value));
}
}
as result i used objects prototype as identifier
class SomeClass {/* ... */};
type TypeOfMap = [
typeof Number["prototype"],
typeof String["prototype"],
typeof Object["prototype"],
typeof SomeClass["prototype"]
];
function getProto<T extends TypeOfMap[number]>(obj: T): T{
return Object.getPrototypeOf(obj);
}
abstract class HandlersMap extends Map{
abstract set<K extends TypeOfMap[number]>(key: K, value: (value: K)=>void): this
abstract get<K extends TypeOfMap[number]>(key: K): ((value: K)=>void) | undefined;
}
const Handlers = new Map() as HandlersMap;
Handlers.set(Number.prototype,(val)=>{});
Handlers.set(Object.prototype,(val)=>{});
Handlers.set(String.prototype,(val)=>{});
Handlers.set(SomeClass.prototype,(val)=>{});
function foo(obj: TypeOfMap[number]){
const handler = Handlers.get(getProto(obj));
if (handler){
handler(obj);
} else {
//unexpected type
}
}