4
votes

I'm liking typescript so far, but find that i need to do type assertion a lot. For example casting an EventTarget to an HTMLAnchorElement is a common use case for me. However to get that, i need to use something like the following:

getTabID(eventTarget: EventTarget) : string {
    // without the following variable, the compiler tells me that .hash 
    // is not a property of EventTarget, which according to the interface, it isn't.
    // So thats fine, i'll cast it to an Element
    let mEventTarget: HTMLAnchorElement = <HTMLAnchorElement>eventTarget
    let mTabID: string
    if(mEventTarget.hash){
        mTabID = mEventTarget.hash.split('#')[1]
    } 
    return mTabID
}

However this means that if I don't want the compiler to throw errors I need to create variables in my functions JUST to do type assertions. I don't mind the extra typing, but these end up in the JS as well and ends up wasting bytes in my js files.

I would like to be able to the following:

getTabID(eventTarget: EventTarget) : string {
    let mTabID: string
    // Do the type assertion in the parameter 
    if(<HTMLAnchorElement> eventTarget.hash){
        mTabID = mEventTarget.hash.split('#')[1]
    } else {
        mTabID = mEventTarget.dataset.tabId
    }
    return mTabID
}

I've had a good look in the docs and SO and can't seem to find any way to do this. Anyone have any ideas?

2
If you are sure that eventTarget will always be a HTMLAnchorElement, why not declare eventTarget: HTMLAnchorElement in the parameter and force callers of getTabID to ensure that it is HTMLAnchorElement?Saravana
You could use eventTarget: EventTarget | HTMLAnchorElement as type, which enables both EventTarget and HTMLAnchorElement as types.Spitzbueb
@Saravana because when I call that function the caller throws an error saying you can't pass an EventTarget to a function that expects an HTMLAnchorElement. @Wernerson I suppose that would stop the errors, but seems like a hack.C02Equinox
@C02Equinox The point is you can do the assertion at the caller end. Like getTabID(target as HTMLAnchorElement). If all this feels like a hassle, I would just type the parameter with any: (eventTarget: any) to turn off type checking.Saravana
Oh that's brilliant! I had tried to use as syntax but couldn't figure out where to use it. Perfect! Thank you!C02Equinox

2 Answers

0
votes

You can use type guards to implement this.

An example would be:

function isAnchor(eventTarget: EventTarget): eventTarget is HTMLAnchorElement {
  return (<HTMLAnchorElement>eventTarget).hash != undefined;
}


function getTabID(eventTarget: EventTarget): string {
  let mTabID: string
  // Do the type assertion in the parameter 
  if (isAnchor(eventTarget)) {
    mTabID = eventTarget.hash.split('#')[1]
  } else {
    mTabID = eventTarget.dataset.tabId
  }
  return mTabID
}

Note: I didn't know what interface dataset was part of but you can make a type guard for it as well.

You can learn more about type guards in the handbook here.

-1
votes

You can perform inline type assertions, by surrounding the assertion with parantheses:

if((<HTMLAnchorElement>eventTarget).hash) {

You might also see what you can do to prevent the need for a type assertion, for example:

getTabID(eventTarget: HTMLAnchorElement) : string {
    let mTabID: string;

    if(eventTarget.hash){
        mTabID = eventTarget.hash.split('#')[1]
    } 

    return mTabID
}

And lastly, watch out for the casing as you mixed EventTarget and eventTarget in one of your examples.