简体   繁体   中英

Typescript - Function return type if I want to return object

Note: Please read through before answering. It looks like a simple question but I'm not sure if it is that simple. Plus I'm new to typescript so go easy on me:p

So here is the use case. I have a model user and I wrote a generic function to check if the user exist based on the email in the DB or not. If it exist it returns the user object.

Now if it would have been any other object then I could have defined the type and carry on with my code but it's the user object I'm getting from DB, not sure how to solve this problem.

I have found the work around for it by mentioning the return type "any" but my soul is not at peace with it. This feels more like a hack than a solution.

Enough talking, here's the code:

export const existingUser = async (email: string): Promise<any> => {
  const foundUser = await User.findOne({ email: email });
  return foundUser;
};

Now as I mentioned above this works, but I tried one different way which was throwing error. I have defined my user model types shown below:

export interface Iuser extends Document {
  profile_picture_url?: string;
  first_name: string;
  last_name: string;
  email: string;
  password: string;
  phone_number?: string;
  is_agree_terms_at: string;
  gender?: Gender;
  role: UserRole;
  isValid: boolean;
}

and then mentioned the Iuser as my return type because that's the type of object I was expecting from the DB. I know it will have other fields once it is added in DB but I don't know any better -_-

export const existingUser = async (email: string): Promise<Iuser> => {
  const foundUser = await User.findOne({ email: email });
  return foundUser;
};

Please help me out. I'm not able to sleep.

First problem- Your function is async , it returns a promise, so you need to wrap Iuser inside a promise type-

// NOTE: This code doesn't work just yet, there are more issues
export const existingUser = async (email: string): Promise<Iuser> => {
  const foundUser = await User.findOne({ email: email });
  return foundUser;
};

Second and main problem - If you check the return type of .findOne - you'll notice it returns a union type - Either the document that it found or null (in case your query does not match anything).

This means the type of foundUser is really, Iuser | null Iuser | null , but you're treating it as Iuser - which is not compatible.

What you can do instead is-

export const existingUser = async (email: string): Promise<Iuser | null> => {
  const foundUser = await User.findOne({ email: email });
  return foundUser;
};

Which will also return either Iuser | null Iuser | null .

Or if you're 100% certain the user must exist-

export const existingUser = async (email: string): Promise<Iuser> => {
  const foundUser = await User.findOne({ email: email });
  return foundUser!;
};

The ! operator asserts the type is not null .

Or, if you'd like throw an exception when the user is not found-

export const existingUser = async (email: string): Promise<Iuser> => {
  const foundUser = await User.findOne({ email: email });
  if (!foundUser) {
      throw new Error('User not found');
  }
  return foundUser;
};

Check out using mongoose with typescript to get a general understanding about how to bake your Iuser type directly into your mongoose model - which will let the type system do all the type inferring work for you in this case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM