1

I want to check if some data has the correct type before passing it as props to a component. I tried this way but it gives an error Teacher' only refers to a type, but is being used as a value here:

const renderSearchResult = () => {
        switch (true) {
            case searchFilter.groups:
                return <GroupInfos groupData={typeof searchResult === Group ? searchResult : null} />
            case searchFilter.teachers:
                return <AddTeacher teacher={typeof searchResult === Teacher ? searchResult : null} mode={MODAL_MODE.update} />
            default:
                return <AddStudentModal student={typeof searchResult === Student ? searchResult : null} mode={MODAL_MODE.update} />
        }
    }
B. Mohammad
  • 2,152
  • 1
  • 13
  • 28
  • The `typeof` operator always returns a string, but you probably want `instanceof` (i.e. `searchResult instanceof Group ? ...`). I suggest doing this logic in the receiving component rather than the TSX, as it doesn't seem like something the view should care about. – Heretic Monkey Jun 22 '21 at 17:40
  • Thanks for the suggestion I will move the logic to the receiving comp. I tried `instanceof` but I still get the same error message from vscode. – B. Mohammad Jun 22 '21 at 17:48
  • Can you put your code on Playground – Alireza Ahmadi Jun 22 '21 at 17:57
  • @B.Mohammad Please check this link: https://stackoverflow.com/questions/44078205/how-to-check-the-object-type-on-runtime-in-typescript – Majid M. Jun 22 '21 at 18:33
  • I'm guessing `Teacher` is an `interface`. If it is, can you include `Teacher` in the question? – programmerRaj Jun 23 '21 at 01:52
  • @programmerRaj `Teacher` is a type, its in the question already :`return ` – B. Mohammad Jun 23 '21 at 09:13

2 Answers2

1

I used the in operator to check if the type has a specific attribute in it,

I did like this:

const renderSearchResult = () => {
    let checkedData: Group | Teacher | Student | null
    switch (true) {
      case searchFilter.groups:
        checkedData = checkTypeData('subject')
        return <GroupInfos groupData={checkedData && checkedData as Group} />

      case searchFilter.teachers:
        checkedData = checkTypeData('rate')
        return (
          <AddTeacher
            hide={() => setSearchResult(null)}
            teacher={checkedData && checkedData as Teacher}
            mode={MODAL_MODE.update}
            displayType={DisplayType.DEFAULT}
          />
        )

      default:
        checkedData = checkTypeData('payments')
        return (
          <AddStudentModal
            student={checkedData && checkedData as Student}
            mode={MODAL_MODE.update}
          />
        )
    }
  }

    const checkTypeData = (key: string) => {
        if (key in searchResult) {
            return searchResult
        } else {
            return null
        }
    }

//// types:
//========

export type Group = {
  id: string;
  title: string;
  subject: string;
  level: string;
  teacher: Teacher;
  students: Student[];
  year: string;
  semester: number;
};

export type Teacher = {
  id: string;
  title: string;
  fullName: string;
  groupIds: GroupId[];
  rate: Rate;
};


export type Student = {
  id: string;
  title: string;
  fullName: string;
  groupIds: string[];
  payments: Payment[];
};

Did still looks too much, I need a better and simpler way.

B. Mohammad
  • 2,152
  • 1
  • 13
  • 28
0

From your question, I think you want to:

  1. narrow the type of searchResult so that typescript will understand what type it is after you check for some differentiating property and
  2. filter the result to the right component according to it's type

Building on B. Mohammad's answer above, use in, but use it in a type-guard to get type safety as well:

function isTeacher(searchResult: Group | Teacher | Student): is Teacher {
    return 'rate' in searchResult;
}

Then you can use it in your render function like so:

const renderSearchResult = () => {
        switch (true) {
            ...
            case searchFilter.teachers:
                return <AddTeacher teacher={isTeacher(searchResult) ? searchResult : null} mode={MODAL_MODE.update} />
            ...
        }
    }
charlieb
  • 306
  • 3
  • 4