1
class MyNumber {
  private __value: number;

  static from(value: any): MyNumber | null {
    if (typeof value === 'number') {
      return new MyNumber(value);
    }
    return null;
  }

  constructor(value: number) {
    this.__value = value;
  }

  to(): any {
    return { type: 'NUMBER', value: this.__value };
  }
}

class MyString {
  private __value: string;

  static from(value: any): MyString | null {
    if (typeof value === 'string') {
      return new MyString(value);
    }
    return null;
  }

  constructor(value: string) {
    this.__value = value;
  }

  to(): any {
    return { type: 'STRING', value: this.__value };
  }
}

class MyBoolean {
  private __value: boolean;

  static from(value: any): MyBoolean | null {
    if (typeof value === 'boolean') {
      return new MyBoolean(value);
    }
    return null;
  }

  constructor(value: boolean) {
    this.__value = value;
  }

  to(): any {
    return { type: 'BOOLEAN', value: this.__value };
  }
}

I want to define a type so that only classes of a specific form are accepted as arguments.

Please tell me what type should for Klass be defined in the code below.

function func(Klass, value: any): any {
  const instance = Klass.from(value);
  return instance ? instance.to() : null;
}

const output = hello(MyNumber, 3);

1 Answer 1

1

The minimum viable typing given the implementation of func() would be this:

function func(Klass: { from(value: any): null | { to(): any } }, value: any): any {
  const instance = Klass.from(value);
  return instance ? instance.to() : null;
}

You could rewrite that with interfaces if you want, but it's the same thing:

interface Toable {
  to(): any;
}
interface Fromable {
  from(value: any): Toable | null;
}    
function func(Klass: Fromable, value: any): any {
  const instance = Klass.from(value);
  return instance ? instance.to() : null;
}

The only information about Klass that you're using is that it has a method named from() which takes any parameter and returns either null or a new object with a to() method taking no parameters and returning any. That allows your example code to work:

const output = func(MyNumber, 3);
const output2 = func(MyString, 1); // accepts any, doesn't it?
const output3 = func(MyBoolean, 100);

But balks at arguments without a proper from() method:

const bad = func(Date, 10); // error
// ------------> ~~~~
// Property 'from' is missing in type 'DateConstructor' but required in type 'Fromable'

const alsoBad = func({ from() { return "oopsie" } }, 123); // error
// ------------------> ~~~~
// Type 'string' is not assignable to type 'Toable | null'

And it doesn't care if the argument is necessarily a constructor, since it doesn't use it to construct anything with new:

const okay = func({ from() { return null } }, 345); // okay
const output = func(MyNumber, 3);

So that all looks good. As an aside I'd suggest avoiding any types unless you can't write something more descriptive. But you didn't ask that, so I'll stop here. Hope that helps; good luck!

Playground link to code

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.