簡體   English   中英

Typescript 映射類型保護

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM