33

I would like to be able to do this

class MyFunc extends ((s: string) => boolean) { ... }

so that an instance of MyFunc can be used as a function which takes a string as input and returns a boolean as follows:

const f = new MyFunc();
const b: boolean = f('someString');

Is this possible in TypeScript?

In languages such as Scala, one can extend the type String => Boolean, and provide an apply method to achieve this.

class MyFunc extends (String => Boolean)
val f = new MyFunc()
val b: Boolean = f("someString")

5 Answers 5

43

Perhaps you are thinking of something like this?

interface FunctionInterface {
    (s: string): boolean;
}

const f: FunctionInterface = s => true;
const b: boolean = f('someString');
Sign up to request clarification or add additional context in comments.

3 Comments

Here is the detail doc for function types: typescriptlang.org/docs/handbook/interfaces.html
Is this possible with non-arrow functions? Something like function myFunc(s) implements FunctionInterface { return true; }
@KasparPoland You can do const myFunc: FunctionInterface = function myFunc..., but that's pretty roundabout. You cannot type a whole function declaration, only a variable.
20

There is no default apply concept in TypeScript, but there are ways of creating typed objects that are also functions.

interface MyCallable {
    (param1: string, param2: number): string;

    prop1: string;
    prop2: number;
    extraMethod: (param1: boolean) => boolean;
}

function makeMyCallable(prop1: string, prop2: number): MyCallable {
    let that = ((param1: string, param2: number) => param1 + param2) as MyCallable;

    that.prop1 = prop1;
    that.prop2 = prop2;
    that.extraMethod = (param1: boolean) => !param1;

    return that;
}

let mc = makeMyCallable("3", 4);

mc("3", 4);
mc.prop1 = "string";
mc.prop2 = 5;
mc.extraMethod(false);

1 Comment

@SalientBrain I've updated the answer to work in TS3.2.
0

If all you want is a simple function to accept a string and return a boolean, you don't need to use a class for this.

const myFunc = (s: string): boolean => {
  return s !== "";  //whatever logic is needed here
};

But, yes you can extend classes in TypeScript

class MyBaseClass {
  constructor() { }

  public doThing = (s: string): boolean => {
    return s !== "";  //whatever logic is needed here
  }
}

class MyFunc extends MyBaseClass {
  constructor() {
    super();
  }
}

const f = new MyFunc();
const b = f.doThing("hi"); //returns a boolean

Updated for response to comment

As mentioned below in another answer, you cannot really new up a class, assign that instance to a variable and then call it as a function. You could do that on the creation though, like this:

class MyBaseClass {
  constructor() { }

  public doThing = (s: string): boolean => {
    return s !== "";  //whatever logic is needed here
  }
}

class MyFunc extends MyBaseClass {
  constructor(private s: string) {
    super();
    this.doThing(this.s);
  }
}

const f = new MyFunc("hi"); //returns a boolean

You can play with the above code on the Typescript playground here

1 Comment

Thanks for the quick answer. But you'd have to write f.doThing('str') to use f as a function, right? The point of extending that function class is for f to be used as a function directly (i.e., called like this: f('str'))
0

Depends on use case. Here several ways. https://typescriptlang.org/play/...

Somehow we imported

type fInterface = (...params: fArgs) => fRet
  • as separate types
type fArgs = [number, string]
type fRet = boolean

No matter - they are interchangeable with Parameters and ReturnType

And we have function implemented wrong

function nop() {}
  1. Manually pick parameters type
function isEqual0(x: fArgs[0], y: fArgs[1]): fRet {
  //return x == y //TS-ERROR: This condition will always return 'false' since the types 'number' and 'string' have no overlap.ts(2367)
  return `${x}` == y
}
  1. With destructing
function isEqual1(...args: fArgs): fRet {
  const [x, y] = args
  return `${x}` == y
}
  1. With overload. Strict usage but during implementation all parameters are any.
function isEqual2(...args: Parameters<fInterface>): ReturnType<fInterface>
function isEqual2(x: any, y: any) {
  return x == y
}
  1. After all we can validate by re-typing (like typing-the-function). Also there will be type validation in parent module in any case.
function isEqual3(x: any, y: any) {
  const valid: typeof  isEqual3 extends fInterface ? true : never = true
  if (!valid)
    throw Error()
  return x == y
}

const _exports = {
  isEqual0, isEqual1, isEqual2, isEqual3, nop
}
, _exportCheck = _exports as  Record<keyof typeof _exports, fInterface> //TS-ERROR The types returned by 'nop(...)' are incompatible between these types.

module.exports = _exportCheck
export default _exportCheck
export {
  isEqual0, isEqual1, isEqual2, nop
}

So many ways to achieve TS-Error if something was wrong.

Comments

-1

If you only have this function in your interface, you can define it like

type FuncType = (s: string) => boolean;

to use it like

const myFunc: FuncType;
function getFunction(): FuncType {}

3 Comments

Your second example of use is incorrect. You would be creating a function called getFunction that returns a function of FuncType, not a boolean.
That second example is returning a function returning a boolean, which would look funny if defined directly.
Yes, that's what I said... And it's not what the author wanted. The author wanted to define a type for a function that takes a string and returns a boolean. What you're doing on the second line is you're defining a function that returns a function. And that is confusing. A function cannot implement an interface, at least not in the current TypeScript version. By looking at the second line, someone might think it's possible.

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.