skip to Main Content

we know that typescript applies structure typing as below example shows:

interface Vector {
   x: number;
   y: number;
}

interface NamedVector {
   x: number;
   y: number;
   name: string;
}

function calculateLength(v: Vector) {
   return Math.sqrt(v.x * v.x + v.y * v.y);
}

const v: NamedVector = { x: 3, y: 4, name: 'zee' };
calculateLength(v);   // compile OK, result is 5

It allowed calculateLength to be called with a NamedVector because its structure was compatible with Vector.

But in term of assignment, it doesn’t use structure typing anymore:

const v: Vector = { x: 3, y: 4, name: 'Zee' };  // compile error, 'name' does not exist in type 'Vector'

according to the definition of structure typing, { x: 3, y: 4, name: 'Zee' } is also compatible with Vector, so why structure typing doesn’t work here?

and what is the Utility Types I can use to describe a type that must contains x and y fields and also some other fields so I can do:

const v: XXX<Vector> = { x: 3, y: 4, name: 'Zee' };

3

Answers


  1. To answer your second question

    interface Vector {
       x: number;
       y: number;
    }
    const v: Vector & {[x:string]: any}= { x: 3, y: 4, name: 'Zee' }; 
    

    TypescriptPlayground

    The first question is not specific enough to answer, in my opinion.

    Login or Signup to reply.
  2. I cannot think of a single use-case where this would be make sense but the simplest way to down-cast is to, well, cast

    const v = { x: 3, y: 4, name: 'Zee' } as Vector;
    

    Of course you won’t be able to access v.name so again, this seems a pointless exercise.

    Login or Signup to reply.
  3. You should not use excess property when use Object literal. So you should use Custom Genernics not to use excess property.

    interface Vector {
       x: number;
       y: number;
    }
    
    interface NamedVector {
       x: number;
       y: number;
       name: string;
    }
    
    function calculateLength(v: Vector) {
       return Math.sqrt(v.x * v.x + v.y * v.y);
    }
    
    type Optional<T, N extends keyof T> = Partial<Pick<T, N>> & Omit<T, N>;
    
    const v: Optional<NamedVector, "name"> = { x: 3, y: 4, name: 'Zee' };
    calculateLength(v);
    

    ref: https://www.typescriptlang.org/docs/handbook/type-compatibility.html#starting-out

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search