简体   繁体   中英

Typescript reference own types method in return type

I'm trying to construct several typed models which can be handled in a similar manner prior to sending to storage. However, I can't figure out a way to determine each models' model::serialize() return type.

Base interfaces/model class:

interface ModelSerialized {}

interface ModelInterface {
  serialize(): ModelSerialized;
}

abstract class Model implements ModelInterface {
  serialize(): ModelSerialized {
    return {};
  }
}

An example User model:

interface UserSerialized {
  firstName: string;
  lastName: string;
}

class User extends Model {
  public firstName: string;
  public lastName: string;

  public constructor(props: UserSerialized) {
    super();

    this.firstName = props.firstName;
    this.lastName = props.lastName;
  }

  get name(): string {
    return `${this.firstName} ${this.lastName}`;
  }

  serialize(): UserSerialized {
    return {
      ...super.serialize(),
      ...{
        firstName: this.firstName,
        lastName: this.lastName,
      },
    };
  }
}

This would live in a separate storage class and handle all models relatively uniformly

interface AuditAttributes {
  updatedAt: string;
}

function serializedAuditModel(
  model: ModelInterface
): ModelSerialized & AuditAttributes {
  return {
    ...model.serialize(),
    ...{
      updatedAt: new Date().toISOString(),
    },
  };
}

A test (w/ expected output in comments)


const userAudit = serializedAuditModel(
  new User({ firstName: "Foo", lastName: "Bar" })
);

console.log("User", {
  firstName: userAudit.firstName, // Property 'firstName' does not exist on type 'ModelSerialized & AuditAttributes'.
  lastName: userAudit.lastName, // Property 'lastName' does not exist on type 'ModelSerialized & AuditAttributes'.
  updatedAt: userAudit.updatedAt,
})

I also created a link to a sandbox

I'd be inclined to make serializedAuditModel() generic in the type S corresponding to the output of the model's serialize() method. Like this:

function serializedAuditModel<S>(
  model: { serialize(): S }
): S & AuditAttributes {
  return {
    ...model.serialize(),
    ...{
      updatedAt: new Date().toISOString(),
    },
  };
}

Then when you call it on a user , you get a more specific type:

const userAudit = serializedAuditModel(user); 
// const userAudit: UserSerialized & AuditAttributes

which should be known to have the properties you care about:

console.log("User", {
  firstName: userAudit.firstName, // okay
  lastName: userAudit.lastName, // okay
  updatedAt: userAudit.updatedAt, // okay
})

Hope that helps; good luck!

Playground link

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