Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: Why does typescript allow me to call function with wrong interface type

Tags:

typescript

Consider the following case. There is no error reported by Typescript while calling func with argument of type One - why?

export interface One {
    common?: string
    one?: string;
}

export interface Two {
    common?: string
    two?: string;
}


export function func(arg: Two) {
    // do something!
}


const one: One = {
    common: 'common',
    one: 'One'
};

const two: Two = {
    common: 'common',
    two: 'Two'
}

func(one);
like image 791
Suresh Nagar Avatar asked Mar 10 '26 07:03

Suresh Nagar


1 Answers

The underlying issue is that One and Two are mutually compatible types as you have defined them.

I don't know if there's a more canonical source of documentation for this, but the (somewhat outdated) TypeScript specification says that all the properties of a target object type T are compatible with the analogous properties of a source type S, then a value of type S is assignable to variable of type T.

In your case, One is assignable to Two because:

  • Two's property common is an optional string value, and so is One's; and
  • Two's property two is an optional string value, and One doesn't have a property of this name.

And Two is assignable to One for analogous reasons:

  • One's property common is an optional string value, and so is Two's; and
  • One's property one is an optional string value, and Two doesn't have a property of this name.

This compatibility is possibly surprising. TypeScript 2.4 introduced weak type detection which will complain if you try to assign any value to an all-optional-property type like One or Two unless they share at least one property. This prevents some crazy stuff like {a?: string} being compatible with {b?: number}, but in your case the fact that common exists in both One or Two disables the weak type checking.


My suggestion here is that if you have two types which are accidentally compatible, you can distinguish them by explicitly adding the problematic property keys to the other types as optional properties of type never or undefined:

export interface One {
  common?: string
  one?: string;
  two?: undefined;
}

export interface Two {
  common?: string
  one?: undefined;
  two?: string;
}

This isn't much different in terms of what you intend to assign to these types:

const one: One = {
  common: 'common',
  one: 'One'
}; // still okay

const two: Two = {
  common: 'common',
  two: 'Two'
} // still okay

but now the compiler sees One and Two as incompatible as desired:

func(one); // error!
//   ~~~ <--  Types of property 'one' are incompatible.

Okay, hope that helps; good luck!

Playground link to code

like image 159
jcalz Avatar answered Mar 12 '26 10:03

jcalz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!