1

Usually in TypeScript i define pretty complex types so I never get this problem but I can't find an easy way to solve it.

type first = number;
type second = number;

let f: first = 1;
let s: second = 2;

const func = (arg1: first, arg2: second) => { };

func(s, f);

I expect to get an error from this code because I define the function with a first argument of type "first" and the second one of type "second" but when I call it I pass two arguments of inverted types

4
  • You just created an alias to number. That's why first and second are compatible. Commented May 6, 2018 at 8:47
  • I know they are compatible but if I create a type for the months and one for the days they should be both number but I want TS to prevent or warn me about switching their position as arguments. Commented May 6, 2018 at 17:43
  • 1
    Currently typescript doesn't support nominal typing. You can tag or brand the type example Commented May 7, 2018 at 4:56
  • 1
    @AlekseyL. if you write that as an answer I'm going to accept it because it's look like what I'm looking for Commented May 7, 2018 at 8:42

2 Answers 2

2

Currently typescript doesn't support nominal typing. As a workaround people use type tagging/branding:

type First = number & { readonly _tag: unique symbol };
type Second = number & { readonly _tag: unique symbol };

let f = 1 as First;
let s = 2 as Second;

const func = (arg1: First, arg2: Second) => { };
func(s, f);  // Error: Types of property '_tag' are incompatible.
Sign up to request clarification or add additional context in comments.

1 Comment

Great answer! This is a clever workaround that I haven't seen mentioned in typescript tutorials. Providing the name 'nominal typing' really helped me with searching for more info too!
0

TypeScript doesn't care about type names (or aliases), just about the shape of the type. Both types first and second are the same type for the compiler, wo you won't get an error.

In fact, due to Structural Typing, this code will also work:

interface I1 {
  name: string;
  age: number;
}

interface I2 {
  age: number;
  name: string;
}

var a1: I1;
var a2: I2;

function log(arg1: I1, arg2: I2): void {
  console.log(arg1, arg2);
}

log(a2, a1);

because, I1 and I2 are also aliases to the same type (both interfaces have the same properties with the same types)

2 Comments

So if I create a type for the months and one for the days they should be both number there's no way TS prevent or warn me about switching their position as arguments?
Well, you could define enumerations for that, that way you wouldn't be able to switch then. In any case, with TS you get intellisense, so it would be easy to detect you're assigning days to months and the other way around. You could also define the type Month as type Month = 1 | 2 | 3 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12. This way, you couldn't assing the number 13 to a variable of type Month. However, this wouldn't prevent errors when both numbers are less than 12. In that case enumerations are better.

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.