skip to Main Content

I’m sure this is the expected behaviour but it looks counter-intuitive for me. Given the following snippet, why is item inferred as { a: number } instead of { b: number }? I was expecting a kind of overriding in Options & { activities: Array<{ b: number }>}.

enter image description here

I’ve discovered that replacing options param type by Omit<Options, 'activities'> & { activities: Array<{ b: number }> } solves the problem, but I would like to understand why TS works this way to get the need of an Omit<>.

Here’s the code so you can copy-paste:

type Activity = { a: number };
type Options = { activities: Activity[] }

const fun = (options: Options & { activities: Array<{ b: number }> }) => {
    return options.activities.map(item => item.b)
}

I was expecting an overriding of activities property so it gets { b: number }[] type.

2

Answers


  1. The & operator is not recursive and doesn’t override anything.

    The goal of typescript is to make code better not worse.

    https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#intersection-types

    Login or Signup to reply.
  2. IMHO a missing feature in TS type system:

    type ActivityA = { a: number };
    type ActivityB = { b: number };
    
    const myArr0: ActivityA[] & ActivityB[] = [
        {a: 1, b: 2},
        {a: 1},         // ERROR, B is necessary
    ]
    
    const item = myArr0[0];         //OK item is ActivityA & ActivityB
    myArr0.map(item => item.b);     //ERROR x is ActivityA
    

    Type intersection is not recursive. Given

    type ActivityA = { a: number };
    type ActivityB = { b: number };
    

    Types ActivityA[] & ActivityB[] and (ActivityA & ActivityB)[] clearly dont behave the same way.

    type ActivityA = { a: number };
    type ActivityB = { b: number };
    
    
    const myArr0: ActivityA[] & ActivityB[] = [
        {a: 1, b: 2},
        {a: 1},         // ERROR, B is necessary
    ]
    
    const myArr1: (ActivityA & ActivityB)[] = [
        {a: 1, b: 2},
        {a: 1},        // ERROR, B is necessary
    ]
    
    const myArr2: ActivityB[] = myArr1;
    
    myArr0.map(x => x.b); //ERROR x is ActivityA
    myArr1.map(x => x.b); //OK    x is ActivityA & ActivityB
    myArr2.map(x => x.b); //OK    x is ActivityB
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search