Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intersection with mapped type broken in function with generic in 4.1.2 #41655

Closed
avaly opened this issue Nov 23, 2020 · 3 comments
Closed

Intersection with mapped type broken in function with generic in 4.1.2 #41655

avaly opened this issue Nov 23, 2020 · 3 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@avaly
Copy link

avaly commented Nov 23, 2020

TypeScript Version: 4.1.2 and 4.2.0-dev.20201123

Search Terms: UpdateQuery, Intersection, Generic

Code

import { UpdateQuery } from 'mongodb';

interface Foo {
  foo: string;
}

function testWithGeneric<TSchema>(): UpdateQuery<TSchema> {
  const update: UpdateQuery<TSchema> = {};

  if (Math.random() < 0.5) {
    const key: string = 'newKey';
    const value: any = true;

    update.$set = {
      ...(update.$set || {}),
      [key]: value
    };
  }

  return update;
}

function testWithoutGeneric(): UpdateQuery<Foo> {
  const update: UpdateQuery<Foo> = {};

  if (Math.random() < 0.5) {
    const key: string = 'newKey';
    const value: any = true;

    update.$set = {
      ...(update.$set || {}),
      [key]: value
    };
  }

  return update;
}

Where the UpdateQuery definition in the mongodb types is defined as:

type DotAndArrayNotation<AssignableType> = {
    readonly [key: string]: AssignableType;
};

type ReadonlyPartial<TSchema> = {
    readonly [key in keyof TSchema]?: TSchema[key];
};

export type MatchKeysAndValues<TSchema> = ReadonlyPartial<TSchema> & DotAndArrayNotation<any>;

export type UpdateQuery<TSchema> = {
    $set?: MatchKeysAndValues<TSchema>;
    // other fields here don't matter
};

Expected behavior:

Code is valid.

Actual behavior:

Only the function testWithGeneric throws an error. But since MatchKeysAndValues is defined as an intersection between ReadonlyPartial<TSchema> and a mapped type of string keys with any values, it should be accepted.

Type '{ [x: string]: any; }' is not assignable to type 'MatchKeysAndValues<TSchema>'. Type '{ [x: string]: any; }' is not assignable to type 'ReadonlyPartial<TSchema>'.

This used to work in version 4.0.5.

Playground Link: https://www.typescriptlang.org/play?ts=4.1.2#code/JYWwDg9gTgLgBAbzgVTAEwIYwKYEUCu2UAnnAL5wBmUEIcA5CBAHYDmEaARvQNwCwAKEHBmOKJQwBjbHABiECIkFwqCgFxwAzjCgjW-AWUGDK+ZpJjAWcHNoDqwGAAsA4tmZFgkgDwAVAMqSTtggGAB8ABQAlBqomDgERMR+gcGhYUoCKpIs2nD46FjYsYUJhCQpQSHhcAC8iGQGynDAlHARALJYTgB0UBjMaLTRcN5wAAw9AKxRmSrZufAA1tjEGtq6bHUMHgDuANKrvM0LzHkAbhgANoQaA6T1OoRNWfMF8dg9ACSa2PD1CBO8x6IIi7yK31+8AAPtCGlEADRAlQAbRWxAAuhpLjdsEDGs0jEJXlA-vgoMx8qVsAYiSYzBYrJTbDAHM4IPgYG4PLpJNESh9EhV5BAMoDXjkzvBwTgBUUhckRRkAQTiSpWu0us4+gMhiARmNJjM5vNJXl0esdHptvQ9odiMdXqcLtdbnB7tsnjTjE6qR9IX9tuL5sDQTLPj9A7D4Ujfaj0Vi4DjCPiDCo6SSyRS-UVaYIgA

@avaly
Copy link
Author

avaly commented Nov 24, 2020

I suspect this might be related to or caused by #40778

@RyanCavanaugh
Copy link
Member

This is a correct error; a legal invocation of your generic function would create an unsound result:

const res = testWithGeneric<{newKey: string}>();
res.$set?.newKey?.toLowerCase();

You should add a type assertion here to indicate that you believe situations like this won't occur

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Dec 3, 2020
@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

3 participants