strblr
strblr

Reputation: 950

Equivalent types but unassignable when using optional index signature : why?

I have the following situation :

type FilterQuery<T> = { [P in keyof T]?: T[P] } & RootQuerySelector<T>;

type RootQuerySelector<T> = {
  $and?: Array<FilterQuery<T>>;
}

class A<T> {
    queries: Array<FilterQuery<T>>

    constructor() {
        this.queries = []
    }

    stuff() {
        const query: FilterQuery<T> = { $and: this.queries }
        console.log(query)
    }
}

The query assignment in stuff() is marked by TS as an error :

const query: FilterQuery<T>
  Type '{ $and: FilterQuery<T>[]; }' is not assignable to type 'FilterQuery<T>'.
    Type '{ $and: FilterQuery<T>[]; }' is not assignable to type '{ [P in keyof T]?: T[P] | undefined; }'.(2322)

Playground Link

I was expecting { $and: this.queries } to be a valid FilterQuery since it's a shape allowed by RootQuerySelector (Btw these types are from the MongoDB official node driver).

Why is there an issue here and how could I solve it ? Thank you.

Upvotes: 0

Views: 49

Answers (1)

Mirco S.
Mirco S.

Reputation: 2610

This is most likely a bug. The compiler has issues evaluating your object because there is no type information yet. He doesn't know what { [P in keyof T]?: T[P] } resolves to before setting a real type for T. If you took { [P in keyof T]?: T[P] } away, he wouldn't complain. But you can trick the compiler (playground):

class A<T> {
    queries: Array<FilterQuery<T>>

    constructor() {
        this.queries = []
    }

    stuff() {
        const query: FilterQuery<T> = {};
        query.$and = this.queries;
        console.log(query)
    }
}

Upvotes: 1

Related Questions