4

I'd like to write a specification for a set of Typescript functions with the implementations in a separate file, and then have tsc check that the actual implementations match the specification.

Something like this:

f-spec.ts:

export declare function foo(s: string, i: int): int;

and then in another source file:

f.ts:

// import { foo } from './f-spec' <<< Doesn't work, gives error
export foo(s: string, i: int) { return i }

When I actually try to include that import, I get an error "Import declaration conflicts with local definition".

How should I declare the function in one file and implement it in a separate file? (Yes, I'm an old C++ guy and thinking about this as if it were a C++ header file, I know. But this is how I need it in this case.)

0

3 Answers 3

4

TypeScript doesn't support forward function declarations like this. In the future it might support forward type/interface declarations, but I don't know if that would help your use case (and it's not available in TS as of TS3.5 anyway)


Workaround: instead of trying to declare your function, maybe give it a type:

type FooFuncType = (s: string, i: number) => number; // int ain't a thing in JS/TS

And then later when you implement your function

function foo(s: string, i: number) {
  return s.length + i;
}

You can create either a value or type artifact that only compiles cleanly if foo conforms to FooFuncType:

const fooIsRightType: FooFuncType = foo; // okay
// or
type FooIsRightType<T extends FooFuncType = typeof foo> = true; // okay

If you do something that doesn't match, like

function foo(s: string, i: number) {
  return s + i;
}

You get errors:

const fooIsRightType: FooFuncType = foo; // error
//    ~~~~~~~~~~~~~~ <-- string is not assignable to number
// or
type FooIsRightType<T extends FooFuncType = typeof foo> = true; // error
//   -------------------------------------> ~~~~~~~~~~
// (s: string, i: number)=>string does not satisdy FooFuncType

Hope that helps; good luck!

Link to code

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

Comments

1

In typescript definitions and implementations are in the same namespace.

If you want to have a type, and an implementation that fulfills that type, they must have different names.

However, when you import a type, you can give it an alias allowing you to use the same name in 2 different files.

I would question the sanity of doing this for every function you write though. Even if it's a habit, it tends to be a good idea to try to mimic what developers in a new ecosystem do, before introducing your own variations to it. Master the rules before you break them.

2 Comments

Yeah, I get that it's a weird case. I don't intend to do it often. I have a particular use case in mind for this though. Given that, how can I import my type with its alias and make sure my implementation conforms to that type?
import { a as alias } is the main syntax. To define a function that uses a specific namespace, use const functionName: functionType = () => { .. implementation .. };
0

As of August 2025 (TypeScript v5.9.2) there are declarations for pretty much anything you might want:


*Which already are, by definition, pure declarations.

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.