Home > other >  constructor parameter type as optional lookup property
constructor parameter type as optional lookup property

Time:02-13

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:

  1. resolving the property of error based on the property of data (i.e if data is an object/array then error is undefined, and if data is null then error and error.message are defined), which should make it so that error is not possibly undefined if i'm trying to pass an errorMessage: 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;
  1. 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)

  2. 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.)

  • Related