Answered
So I have following interfaces: MovieData
export interface MovieData {
Poster: string;
Title: string;
Plot: string;
imdbID: string;
}
and interface ResponseError
export interface ResponseError {
Response: 'False',
Error: string,
}
I also have function getMovie() thet returns Promise, resolve type is MovieData , and reject type is ResponseError
import { MovieData } from './types/MovieData';
import { ResponseError } from './types/ReponseError';
const API_URL = 'https://www.omdbapi.com/?apikey=**********';
export function getMovie(query: string): Promise<MovieData | ResponseError> {
return fetch(`${API_URL}&t=${query}`)
.then(res => res.json())
.catch(() => ({
Response: 'False',
Error: 'unexpected error',
}));
}
In FindMovie function component I invoke handleSubmit function, and pass search string inside getMovie function. In then() method of promise I want to check either promise was rejected , or fullfiled. In case rejected - I check if res object has property Error. type of res - if you hover mouse over res property in then() - res: MovieData | ResponseError
import { useState } from 'react';
import { getMovie } from '../../api';
export const FindMovie: React.FC = () => {
const [search, setSearch] = useState<string>('');
const [error, setError] = useState<boolean>(false);
const handleSubmit = () => {
if (search === '') {
return;
}
getMovie(search)
.then(res => {
if (res?.Error) {
console.log(res?.Error)
}
});
setError(false);
};
QUESTION!!!!!!!!
in terminal I recieve error: Property 'Error' does not exist on type 'MovieData | ResponseError'. Property 'Error' does not exist on type 'MovieData'.
I tried to use import separetly interface ResponseError to file with findMovie function component
import { ResponseError } from '../../types/ReponseError';
and to perform next check
.then(res => {
if (res instanceof ResponseError) {
console.log(res?.Error)
}
});
But I recieve even wierder error message: Attempted import error: 'ResponseError' is not exported from '../../types/ReponseError'.
Will be glad for every advise.
CodePudding user response:
You need a type guard here to check if your object is of type ResponseError
.
You cannot use instanceof
here, since that is used to check if an object belongs to a certain class
.
Whereas in your case, you are using interface
and type
.
Defining a type guard like:
function isResponseError(obj: any): obj is ResponseError {
return obj.Error !== undefined;
}
and then doing:
.then(res => {
if (isResponseError(res)) {
console.log(res.Error)
}
});
should solve your problem.
You can check out this stackoverflow answer for more info on type guards vs instanceof
: How to check the object type on runtime in TypeScript?
CodePudding user response:
So, thats how I implemented type guard
if (res?.Title === undefined) {
setError(true);
}
But I also completly rewrote fetch request. Honestly , now its wierd , result
variable will be of Type MovieData errelevent of object content. But it Just Works.
In the question problem was: I was checking for property of Moviedata
type object - typescript said that ResponseError
interface doesn't have that property - because promise returned object of either MovieData
or ResponseError
;
export async function getMovie(query: string): Promise<MovieData > {
const res = await fetch(`${API_URL}&t=${query}`);
const result = await res.json();
if (result.response === 'False') {
throw new Error(`${result.statusText}`);
}
return result;
}