typescripttypescript1.7

what is difference between this 2 typeScript code?


what is difference between this 2 typeScript code?(I use typeScript 1.7.5)

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): {color: string; area: number} {
  var newSquare = {color: "white", area: 100};
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

var obj = {color1: "black"};
var mySquare = createSquare(obj);

when is compile not error but below code production error.

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): {color: string; area: number} {
  var newSquare = {color: "white", area: 100};
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

var mySquare = createSquare({color1: "black"});

error:

test.ts(18,30): error TS2345: Argument of type '{ color1: string; }' is not assignable to parameter of type 'SquareConfig'. Object literal may only specify known properties, and 'color1' does not exist in type 'SquareConfig'.


Solution

  • Both of your examples have the same (perceived) error, which is that you have specified a property that isn't known to SquareConfig, which often means you have mis-typed a property name.

    In your case you have specified color1 where you probably intended to use color.

    This code would have compiled using older versions of TypeScript before this additional feature of checking for unspecified properties was added.

    Fixes...

    Option One, specify the correct property:

    var mySquare = createSquare({color: "black"});
    

    Option Two, you are deliberately intending to include some other property, use a type assertion to tell the compiler you know better than it does (as long as you are sure you do in fact know better than it does!):

    var mySquare = createSquare(<SquareConfig>{color1: "black"});
    

    Update based on comment

    The compiler is more strict the less "degrees of separation" you have... for example:

    // Error
    var obj: SquareConfig = {color1: "black"};
    
    // OK
    var obj = {color1: "black"};
    var obj2: SquareConfig = obj;
    

    Let's look at the first example, we are saying "I intend to create a SquareConfig". The compiler says, "well, there are no required items as everything is optional, but you are creating the object with a property I don't recognise - so I'll warn you".

    The second example is slightly different. We are saying "I intend to use an object that I have as a SquareConfig". The compiler says, "is the object you intend to use missing any required properties... and does each property have the correct type to be a structural match for a SquareConfig - yes."

    If the second scenario warned you about properties that don't exist on the target structure, you'd wouldn't be able to take advantage of the uber-polymorphism that a structural type system offers.