ianstormtaylor / superstruct

A simple and composable way to validate data in JavaScript (and TypeScript).
https://docs.superstructjs.org
MIT License
6.96k stars 223 forks source link

[Question|Feature] Add functions to an interface #1176

Closed JoniJnm closed 1 year ago

JoniJnm commented 1 year ago

Is there any way to have functions in a Interface?

Having a user interface:

interface User {
  id: number;
  name: string;
  lastName: string;
}

I want to define a function to get the fullName:

interface User {
  id: number;
  name: string;
  lastName: string;

  fullName(): string;
}

So i want later to create an user and them call the functions:

const user = create(
  {
    id: 1,
    name: 'John',
    lastName: 'Doe',
  },
  User,
);

console.log('full name', user.fullName());

There is a func type, but the original data won't have this function.

This works but I don't know if there is a better solution:

import {object, number, string, create, Describe, Struct, defaulted} from 'superstruct';
import {Validator} from 'superstruct/dist/struct';

function defineFunc<FUN_T>(fn: FUN_T): Struct<FUN_T, null> {
  const validator: Validator = value => {
    const type = typeof value;

    if (type === 'function') {
      return true;
    }

    return `Expected a function, but received: ${type}`;
  };

  return defaulted(new Struct({type: 'func', schema: null, validator}), () => fn, {
    strict: true,
  });
}

interface User {
  id: number;
  name: string;
  lastName: string;

  fullName(): string;
}

const User: Describe<User> = object({
  id: number(),
  name: string(),
  lastName: string(),

  fullName: defineFunc(function (this: User) {
    return [
      this.name,
      this.lastName,
    ].join(' ');
  }),
});

const user = create(
  {
    id: 1,
    name: 'John',
    lastName: 'Doe',
  },
  User,
);

console.log('full name', user.fullName());