-1

I'm looking for a transform function or methodology that would allow me to retain typescript's ability to infer types (get type checking and code hints) on a resulting object. In the example below, C (and related E) are the scenarios which are proving problematic.

class Wrapper<T> {
    constructor(private val: T) { }

    value(): T {
        return this.val;
    }
}

// A 
var wrappedNum = new Wrapper(1);
// Typescript infers value() and that it returns a number
wrappedNum.value().toFixed(1); 

// B
var wrappedNumArray = [1, 2, 3].map(function(val) { return new Wrapper(val); });
// Typescript infers that for each element in array, value() returns number
wrappedNumArray[0].value().toFixed(1); 

// C
// ** Typing of properties is lost in this transformation **
function wrapObject(obj) {
    var targ = {};

    for(var key in obj) {
        targ[key] = new Wrapper(obj[key]);
    }

    return targ;
}

var wrappedObj = wrapObject({a: 1});
// Typescript does not infer the existence of `a` on wrappedObj
wrappedObj.a; 

// D
// Typescript infers `a` and its type
({ a: 1 }).a.toFixed(1); 

// E
// ** Typing of properties is lost in this transformation **
function noop(obj) {
    return obj;
}

// Typescript does not infer the existence of `a` on noop transformed object
noop({ a: 1 }).a; 

// F
function getValue() {
    return { a: 1 };
}

// Typescript infers the existence of `a` and its type
getValue().a.toFixed(1); 

Is there are a way C & E could be structured such that type inference would work while being agnostic to the structure of the object passed?

bjnsn
  • 2,710
  • 2
  • 16
  • 14

1 Answers1

1

C

For C, I can't think of a way to do that. A compromise is to use a dictionary-like type and then map it out with generics.

For example:

function wrapObject<T>(obj: T) {
    var targ: { [key: string]: Wrapper<T>; } = {};

    for(var key in obj) {
        targ[key] = new Wrapper<T>(obj[key]);
    }

    return targ;
}

var wrappedObj = wrapObject({a: 1});
wrappedObj["a"].value; // ok

E

Use generics:

function noop<T>(obj: T) {
    return obj;
}

noop({ a: 1 }).a; // works

Read more about generics in the Handbook.

Community
  • 1
  • 1
David Sherret
  • 101,669
  • 28
  • 188
  • 178
  • Hmmm. That works is correct for E - but for C that is incorrect. `wrappedObj.a` appears to have an inferred `number` type, but is actually a `Wrapper`. This type system coercion fits with the return type annotation on `wrapObject`. – bjnsn Sep 16 '15 at 22:45
  • @bjnsn whoops, missed that detail. For what I can think of right now, it's not possible to do that. – David Sherret Sep 16 '15 at 22:55
  • Thanks for the effort. I've been racking my brain and haven't come up with anything either. I'm hoping someone who is more familiar with Typescript than I will swoop in! – bjnsn Sep 16 '15 at 23:48