[英]Typescript mapped Type Guard
我有 function 可以獲取多種類型作為參數(在我的例子中是“獲取”代理處理程序)並且應該根據其類型不同地處理該參數。
對於普通的 js,我知道如何處理它,就像這樣:
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*/
}
}
但在 typescript 中,在保持類型跟蹤方面,我想到的只是類型保護
// 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*/
}
}
但與普通的 js 相比,它看起來很傻(會很快失去控制並且還會進行很多不必要的操作),所以:
TS 是否有等效的解決方案?
示例 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);
可能使用原型本身作為關鍵
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));
}
}
結果我使用對象原型作為標識符
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
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.