i've just started creating constructors based on my interfaces and i'm stuck here, where "Property 'message' does not exist on type '{ message: string; } | undefined'" in the errorMessage parameter's lookup type:
interface fetchResponse {
data:null|object|any[];
error?:{
message:string;
};
};
interface FetchResponse extends fetchResponse {};
class FetchResponse {
constructor(data:fetchResponse["data"], errorMessage?:fetchResponse["error"]["message"]) {
this.data = data;
this.error = errorMessage ? {
message: errorMessage,
} : undefined;
};
};
i found the following possible ways to fix this, but i've been able to successfully implement none:
- resolving the property of
error
based on the property ofdata
(i.e ifdata
is an object/array thenerror
is undefined, and ifdata
is null thenerror
anderror.message
are defined), which should make it so thaterror
is not possibly undefined if i'm trying to pass anerrorMessage
: the only way i found to maybe do that is with a union (according to this SO post), but imitating that as seen below only caused typescript to flag 2 more problems which i'm clueless about in the latter half of the code
interface fetchResponsePositive {
data:object|any[];
};
interface fetchResponseNegative {
data:null;
error: {
message:string;
};
};
type fetchResponse = fetchResponsePositive | fetchResponseNegative;
overloading (according to this OS post)? this is my first ever exposure to the concept of overloading, after looking it up i understand the concept but cant figure out how to implement it here in a way that solves the issue (or whether it's even a solution to this)
adding a definite assertion to the
fetchResponse["error"]["message"]
lookup: i just have no idea how to do that, i placed the exclamation mark in every conceivable spot to no success
CodePudding user response:
Here's a utility type that should allow you to get around this issue (inspired by type-fest's Get
helper):
type Get<T, K> = T extends undefined ? undefined : K extends keyof T ? T[K] : unknown;
It will fetch the type at a given key, even when the base type is optional. You can use it like this:
class FetchResponse {
constructor(data:fetchResponse["data"], errorMessage?:Get<fetchResponse["error"], "message">) {
this.data = data;
this.error = errorMessage ? {
message: errorMessage,
} : undefined;
};
};
It should evaluate to string | undefined
, which I assume is what you want. (If you don't want undefined
there, you can always use the Exclude
utility type to remove it from the union.)