2

I have an Angular 2 project with TypeScript. I don't understand why TypeScript live compiler is complaining about the info.map?

Error message: unresolved function or method map()

When I run it in the browser, is working just fine, but I don't understand why it happens and more importantly how TypeScript determines in which if /else branch I'm in.

The code:

let addInfo = (info: string|string[]) =>  {
        if(_.isString(info)){

            console.log('info is a string');
            infos.push(info);

        }else if(_.isArray(info)){

            console.log('info is an array');
            info.map( x => { infos.push(x) }); // here is the compiling error- map is red.
        }
 }

Here is a snapshot:

enter image description here

2
  • 1
    Typescript compiler doesn't recognise lodash's function call as a type check. You can try "if(info instanceof String)" and in the else branch typescript can assume info is array. Commented Sep 30, 2016 at 14:26
  • 1
    Do you use github.com/DefinitelyTyped/DefinitelyTyped/blob/master/lodash/… ? Commented Sep 30, 2016 at 14:31

2 Answers 2

3

Typescript compiler doesn't recognise lodash's function call as a type check. You can try "if(info instanceof String)" and in the "else" branch typescript can assume the "info" is array.

This works for me in the typescript playground:

let addInfo = (info: string|string[]) =>  {
    if(info instanceof String){
        info;
    } else {
        info.map(s => s);
    }
 }

Update

Thanks to @Tamas Hegedus, shared knoweledge about custom type-guards. I haven't heard about them before. I've decided to put here quotation from Typescript documentation about User-Defined Type Guards:

It just so happens that TypeScript has something called a type guard. A type guard is some expression that performs a runtime check that guarantees the type in some scope. To define a type guard, we simply need to define a function whose return type is a type predicate:

function isFish(pet: Fish | Bird): pet is Fish {
    return (<Fish>pet).swim !== undefined;
}

pet is Fish is our type predicate in this example. A predicate takes the form parameterName is Type, where parameterName must be the name of a parameter from the current function signature.

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

4 Comments

Yes, that is a good explanation. Thanks @TSV :) But do you know if it's possible to make Typescript recognize the lodash functions? - they are so nice compared to the instanceof / or other native JavaScript checks.. Webstorm is underlining in red all project files that have this types errors and i have multiple files in red because of this. I don't know which are the real errors and which are not. Is annoying..
I do understand your point. I'm not sure typescript understands another type checknig except it's own... Are you using "lodash.d.ts"? If so, probably I'm right...
@Alon Typescript has user-defined type guards, and lodash.d.ts takes advantage of them. Just use it and the compiler will not complain anymore.
You should really use typeof info === 'string' -- instanceof is going to give you false positives on wrapped String objects which won't behave the way you expect. It's also likely to be faster to use typeof
3

Simple solution:

I had the @types/lodash/index.d.ts file, but i believe was an older version. As soon as I installed the new version - everything worked as expected.

So for people with Angular2 CLI project, just run: npm install @types/lodash :)

1 Comment

I didn't know about user-defined type-guards. Thank you, guys!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.