简体   繁体   中英

Return dynamic compile time type in Typescript?

I've written a method to imitate the Null conditional operator / Elvis operator , including autocomplete and array support :

Say I have this object :

var o = { a: { b: { c:[{a:1},{a:2}] , s:"hi"} } };

I can access the second element in the array and fetch a :

if ( n(o, (k) => k.a.b.c[1].a) == 2 ) 
 {
    alert('Good'); //true
 }

What I've done was to cause the expression to be sent as a function , which then I can parse as string :

function n<T>(o :T , action : (a:T)=>any):any { 
    let s = action.toString().toString().split('return')[1].split('}')[0].split(';')[0];
    s = s.replace(/\[(\w+)\]/g, '.$1'); //for  array access
    s = s.replace(/^\./, '');    //remove first dot        
    var a = s.split('.');
    for (var i = 1, n = a.length; i < n; ++i) {   //i==0 is the k itself  ,aand we dont need it
        var k = a[i];
        if ( o && o.hasOwnProperty(k)) {
            o = o[k];
        } else {
            return null;
        }
    }
    return o;
}

It does work as expected , but I have a small problem.

The signature of the method returns any :

function n<T>(o :T , action : (a:T)=>any) :any 
                                           ^^^ 

Question:

Is there any option that the return value will more specific ( or even exact) as the prop I'm trying to access ?

So n(o, (k) => kabc[1].a) will be :number and n(o, (k) => kabs) will be :string

Is it possible ? if not , is there a way to make return value to be more "typi" ?


Link for comment

You can just add an extra type parameter for the return value and let the compiler figure out that the type parameter is the return type of the expression:

var o = { a: { b: { c: [{ a: 1 }, { a: 2 }], s: "hi" } } };
function n<T, TValue>(o: T, action: (a: T) => TValue): TValue | null {
    let s = action.toString().toString().split('return')[1].split('}')[0].split(';')[0];
    s = s.replace(/\[(\w+)\]/g, '.$1'); //for  array access
    s = s.replace(/^\./, '');    //remove first dot        
    var a = s.split('.');
    let result: any = o
    for (var i = 1, n = a.length; i < n; ++i) {   //i==0 is the k itself  ,aand we dont need it
        var k = a[i];
        if ( result && result.hasOwnProperty(k)) {
            result = result[k];
        } else {
            return null;
        }
    }
    return result;
}


let nr = n(o, (k) => k.a.b.c[1].a) // is number | null

var str = n(o, (k) => k.a.b.s) // is string | null

Note The |null part is optional but makes sense in the context of your implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM