2

If you declare an interface and function that have the same name, then use it later on with both cases, how does typescript know which you are referencing? Here is an example below:

interface Person {
    name: string;
}

function Person(person : Person) {
    return "Hello, " + person.name;
}

function Test(persons: Person[]) {
  return persons.map(person => Person(person));
}

Is this a "best practice" way to code this? This works when I run it locally, but I can't tell if this is how you should write typescript. But the Person interface and function are suppose to represent the same thing so it somewhat makes sense. Declaration Merging explains how it merges together different declarations together, but it does not explain how it would handle merging a interface and function and what that would represent.

2 Answers 2

4

The code is perfectly acceptable, but if it confuses you, don't do it.

I don't know if there's a canonical piece of documentation about this, but types and values are distinct concepts in TypeScript. Type names and value names both appear in valid TypeScript code, but since references to them generally appear in different contexts, you can have a type with the same name as a value, and TypeScript will not be confused (you might be confused, though). Types in TypeScript only exist at design-time/compile-time and are erased from the runtime code, whereas values are generally valid JavaScript and persist in the runtime code. If you declare a type and a value with the same name, this is not really considered declaration merging, since the declarations don't really interact with each other the way that, say, two interface declarations with the same name would.

The distinction between types and values definitely trips up developers who think that they can do something like function oops<T>() { new T(); }, not realizing that the first T can refer only to a type and the second T must refer to a constructor value. This confusion is probably caused by the fact that some declarations do create both a type name and a value name at the same time. A class declaration is a big one; class Foo {} makes the type Foo which refers to an instance of the class, but it also makes the value Foo which is the class's constructor.


If you look at the "basic concepts" chart, you will see which declarations create which sort of thing. An interface creates a named type, and a function creates a named value. When you write

interface Person {
    name: string;
}

you have declared a type named Person. When you write

function Person(person : Person) {
    return "Hello, " + person.name;
}

the first Person is declaring a value. The second Person is a type annotation, which refers unequivocally to the type declared by the interface.

When you write

function Test(persons: Person[]) {
  return persons.map(person => Person(person));
}

the Person[] is a type annotation, referring to the interface, while the Person in person => Person(person) is in the return value of a lambda expression, which is therefore interpreted as the function.


I hope my explanation makes sense to you; understanding the distinction between types and values is vital to understanding TypeScript. Good luck!

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

1 Comment

Good answer - nice job explaining the difference between types and values.
0

TypeScript can usually determine which symbol you're referring to using context. For example, a TypeScript interface can't be called as a function (like Person()) - so it knows to use the Person function instead.

However, even though TypeScript can navigate its way through code with duplicate names, it is best practice to avoid this practice. It makes your code more confusing and hard to reason about for both you and other developers. There's no room for confusion if each thing has its own unique name.

In your example, I would recommend renaming your Person function to something like greetPerson() or maybe logPerson(), since this is more descriptive about what the function is doing to the Person object.

Regarding declaration merging - this is a somewhat unrelated concept used to merge similar things (like two interfaces) together. Different TypeScript constructs (like a class and an interface) can't be merged together.

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.