Raphael Castro
Raphael Castro

Reputation: 1148

Why isn' t typescript recognizing the union type in this statement?

I have the following code:

type testUnion = Array<any> | string;

class testClass {
testProp: testUnion;
}

const bar = new testClass()
bar.testProp.forEach(...) //property forEach does not exist on type testUnion

However testUnion is an array OR a string and the property for each exists on the Array class. Why is typescript not seeing it as an Array or a String. The only intelisense I get is a method 'valueOf'

any ideas?

EDIT
full code below, the loadTrait method in the Developer class is what is in question, I also included the Trait class and all the relevant interfaces just incase there are any other suggestions.

interface devInit {
    locations: Array<Location>;
    traits: Array<Trait>;
    props: developerProp;
    name: string;
}

interface developerProp {
    acceptedMaritalStatuses: maritalStatusType;
    ageTop: number;
    ageBottom: number;
    income: number;
    majorCCRequired: boolean;
}
class Developer {
    locations: traitLocationType;
    props: developerProp;
    name: string;
    private traits: Array<Trait> = [];
    constructor(init: devInit) {
        Object.assign(this, init);
        $notesApi.subscribe((_notes) => {
            this.notesApi = _notes;
        });
    }
    private notesApi: notesApiType;
    //only load after traits have been loaded.
    private loadExternalNotes() {
        //@ts-ignore
        if (_notes === '') return;
        this.locations.forEach((_location) => {
            const gifts = new Note(
                'gifts',
                this.notesApi[this.name][_location.name].gifts
            );
            const notes = new Note(
                'gifts',
                this.notesApi[this.name][_location.name].notes
            );
            _location.addNote(gifts);
            _location.addNote(notes);
        });
    }
    private loadTraits() {
        this.traits.forEach((_trait) => {
            _trait.runRules();
            if (!_trait.key) return;
            if (_trait.key === 'locations') {
                if(Array.isArray(_trait.value))
                _trait.value.forEach((_traitValue) => {
                    this.locations.push(_traitValue);
                });
            }
        });
    }
}

class Trait {
    constructor(traitKey: traitKeyType, traitValue: traitValueType) {
        this._key = traitKey;
        this._value = traitValue;
    }
    private _key: traitKeyType;
    private _value: Array<any> | string;
    private status = false;
    private notes: Array<Note> = [];
    private rules: Array<Rule> = [];
    get key() {
        if (!this.status) return null;
        return this._key;
    }
    get value() {
        if (!this.status) return null;
        return this._value;
    }
    addRule(rule: Rule) {
        this.rules.push(rule);
        return this;
    }
    runRules() {
        const getInfoFromRules = (_rule: Rule) => {
            _rule.run();
            this.notes.push(_rule.note);
            return _rule.status;
        };
        this.status = this.rules.map(getInfoFromRules).indexOf(false) === -1;
    }
}
type traitValueType = Array<any> | string;
// | maritalStatusType
// | traitLocationType
// | traitLocationType
// | boolean;

type maritalStatusType = 'married' | 'coHab' | 'singleMale' | 'singleFemale'[];
type traitLocationType = Array<Location>;

Upvotes: 0

Views: 41

Answers (1)

bryan60
bryan60

Reputation: 29325

because it can be an array OR a string. TS doesn't know which it is, you have to tell it...

you can use a type check:

if (Array.isArray(bar.testProp)) {
  bar.testProp.forEach(...)  // this is fine 
}

or if you KNOW it's in fact an array, you can use a type assertion:

(bar.testProp as Array<any>).forEach(...) // also fine

Upvotes: 2

Related Questions