4

I've got the following code:

let item = object[] | object;
if (a === true) {
    item = [];
    // would like to do something like item: object[] = []
    (item as object[]).push(...);
else if (b === true) {
    item = {};
    // would like to do something like item: object = {}
    (item as any).prop = ...
}
// do stuff with item

My problem is that because item can be either an object or a list of objects, I then have to cast item in order for typescript to allow me to work with it. Is there any way to declare the type of object on its initialization, so these casts are unnecessary?


Just to clarify, I DO want item to be typed, I just want that typing to be specified after it is defined.

perennial_
  • 1,798
  • 2
  • 26
  • 41

3 Answers3

2

The idiom I'm familiar with is to declare a more narrowly-typed temporary variable and then assign it back to the wider-typed variable. For example:

type IndexableObject = { [k: string]: any };
let item: IndexableObject[] | IndexableObject;
declare let a: boolean;
declare let b: boolean;
if (a === true) {
    let itemArray: IndexableObject[] = [];
    itemArray.push({ hey: 'you' }, { whats: 'up' });
    item = itemArray;    
} else if (b === true) {
    let itemObject: IndexableObject = {};
    itemObject.prop = 'hello';
    item = itemObject;
}

I know you'd rather not introduce such a variable, but my experience is that doing anything else is just fighting with TypeScript, which is usually fruitless. Good luck!

EDIT: It looks like you're basically running into this situation. As you can see in that GitHub issue, nobody is even thinking of implementing the kind of type narrowing control flow you want. So the temporary variable is the only reasonable way to go, as far as I can see.

jcalz
  • 264,269
  • 27
  • 359
  • 360
1

You could use Type Assertion, like this:

let item: Any 
if ( some condition ) {
let mynewtype = (item as string)
// use mynewtype as string }
Anzar Alim
  • 47
  • 8
-5

You can use any. Then item can be anything without compiler errors.

let item: any;
if (a) {
   item = [];
   item.push('new thing');
} else {
   item.prop();
}

From the TS documentation:

The any type is a powerful way to work with existing JavaScript, allowing you to gradually opt-in and opt-out of type-checking during compilation. You might expect Object to play a similar role, as it does in other languages. But variables of type Object only allow you to assign any value to them - you can’t call arbitrary methods on them, even ones that actually exist

There is also a good discussion here about any vs. Object.

nick
  • 1,880
  • 17
  • 27
  • This solution defeats the entire purpose of typing a variable in the first place (arguably the entire purpose of using typescript). While it has its use cases, i'm hoping for a superior solution here. – perennial_ Jul 26 '17 at 22:48
  • I completely agree. However, if you don't have control of what `item` will be (which it appears you don't) then you may need the flexibility of `any`. – nick Jul 26 '17 at 23:18