0

I have a case where a variable could be type A or type B. Then using a If I know what type the variable is and I apply an appropriate response.

I got TSLINT errors.

function checkIfItsAString(foo: String | Number): boolean {
  return foo instanceof String;
}

function example2(foo: String | Number) {
  if (checkIfItsAString(foo)) {
    foo.charAt(5);

    return;
  }
}

enter image description here

enter image description here

How can I say to typescript,

starting now, this variable is of type "String"

6
  • 2
    Is staticIsAnError actually a type predicate? Give a minimal reproducible example. Commented Sep 20, 2019 at 7:15
  • @jonrsharpe I've added a generic, reproductible example Commented Sep 20, 2019 at 7:23
  • So it's not a type predicate. The compiler doesn't know you expect that check to narrow the type. Commented Sep 20, 2019 at 7:31
  • 1
    @GrégoryNEUT you can cast it x as ManuallyCastType but I'd suggest using a type predicate checkIfItsAString(foo: String | Number): foo is String this way you don't have to manually tell the compiler every time by casting the value Commented Sep 20, 2019 at 7:35
  • 1
    Did you follow the link I posted? Commented Sep 20, 2019 at 7:36

2 Answers 2

1

The compiler can't infer anything useful from the boolean return type of checkIfItsAString; the name of that function tells other human readers of the code what you expect, but that doesn't help the compiler at all.

Instead, you need to be explicit that this is a type predicate, i.e. inform the compiler that it can use this to narrow the type of a variable based on the result. Instead of just boolean, it is going to return whether foo is String:

function checkIfItsAString(foo: String | Number): foo is String {

The actual implementation doesn't need to change, this is just extra information for the compiler.

Sign up to request clarification or add additional context in comments.

Comments

1

You can use a type predicate to have the compiler automatically narrow down the types. Your predicate already works, to make it a type predicate you just have to say what it implies about the value:

function checkIfItsAString(foo: String | Number): foo is String {
//  tell the compiler true means it's a string -> ^^^^^^^^^^^^^
  return foo instanceof String;
}

This lets the compiler determine the type automatically:

function example2(foo: String | Number) {
  if (checkIfItsAString(foo)) { //foo is a String

    foo.charAt(5);

    return;
  }

  foo.toFixed(""); //foo is a Number
}

Live demo on TypeScript Playground

Alternatively, you can use the in operator directly which will do type elimination from a list of types:

function example2(foo: String | Number) {
  if ("charAt" in foo) {
  //   ^^^^^^ this only exists on String not on Number, so it's a String
    foo.charAt(5);

    return;
  }

  foo.toFixed(2); //a number, since it doesn't have "charAt"
}

Live demo on TypeScript Playground

This is more useful for one-off simpler checks, so you don't need an entire predicate to handle it. It can be used to narrow down types, if that is a use case. Here is a contrived example that uses in to eliminate types in several steps.

/* 
 * ake a Nnumber, String, array of Numbers, or the HTMLCollection array-like:
 * for Number - the value
 * for HTMLCollection - the length
 * for array of number - the sum + the length
 * for string - the length + the trimmed length
 */
function dummyExample(x : Number | String | Number[] | HTMLCollection) : number {
  if ("length" in x) { // String | Number[] | HTMLCollection
    let totalLength: number = x.length;

    if ("slice" in x) { // String | Number[]
      if ("reduce" in x) { // Number[]
        return x.reduce((a: number, b: Number) => a + b.valueOf(), 0) + length;
      } else { // String
        return x.trim().length + totalLength;
      }
    } else { // HTMLCollection
      return totalLength;
    }
  } else { // Number
    return x.valueOf();
  }
}

Live demo on TypeScript Playground

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.