8

I'm trying to write a Typescript interface, then write a class that implements that interface.

The problem is that I can't seem to get the method signatures from the interface to apply to the class.

Here's a slimmed-down example:

export interface Foo {
  bar(value: string): void;
}


export class MyFoo implements Foo {
  // ✔️ Typescript error:
  // Property 'bar' is missing in type 'MyFoo' but required in type 'Foo'
}


export class MyFoo implements Foo {
  // value is inferred as `any` instead of `string`, 
  // and there aren't any errors with the return type mismatch
  bar(value) { return true; }
}

It seems that the compiler is aware that the bar method should exist, but doesn't preserve the signature of it for some reason.

4 Answers 4

8

seems that the compiler is aware that the bar method should exist, but doesn't preserve the signature of it for some reason.

Correct. Reasons are covered here : https://github.com/Microsoft/TypeScript/pull/6118#issuecomment-216595207

So it is made the responsibility of the developer to add the annotations they need.

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

1 Comment

Thanks for that link. TLDR: when a class implements an interface, TypeScript enforces - but doesn't transfer - type information from the interface to the class, so the class and interface may end up being incompatible. Unless you copy the annotations. TS interfaces, type aliases, and classes are all different things. :-/
2

Type any can be assigned to any other type in TypeScript. You should specify the type for value in the implementation of the bar method. Then. if it's anything other than string, the compiler will throw an error.

You can force your TypeScript compiler not to allow any implicit any by adding the following line to your tsconfig.json file.

"noImplicitAny": true

In general, the best practice is to explicitly add the type for function parameters and return values and avoid any to the extent possible.

Comments

1

So it looks like there actually is some type checking happening, despite the signature not being preserved exactly.

If I try to implement my Foo class with incompatible types it will complain.

export interface Foo {
  bar(value: string): string;
}

export class MyFoo implements Foo {
  // ✔️ Typescript error:
  // Type '(value: boolean) => boolean' is not assignable to type '(value: string) => string'.
  bar(value: boolean) { return boolean; }
}

Comments

0

If you don't want to rewrite the method type, you can use the Parameters utility type to extract the type out from the original implemented interface. This is mainly useful when the class that you're implementing is imported from a third party package and the parameter type is too complicated to copy.

export interface Foo {
  bar(value: string): void;
}

export class MyFoo implements Foo {
  bar(value: Parameters<Foo['bar']>[0]) { return true; }
}

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.