Skip to content

No-op mapped type not assignable; but original type is assignable #38235

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

Closed
AnyhowStep opened this issue Apr 29, 2020 · 4 comments · Fixed by #38761
Closed

No-op mapped type not assignable; but original type is assignable #38235

AnyhowStep opened this issue Apr 29, 2020 · 4 comments · Fixed by #38761
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@AnyhowStep
Copy link
Contributor

AnyhowStep commented Apr 29, 2020

TypeScript Version: 3.8.3

Search Terms:

no-op mapped type, assignable

Code

type Foo<IdentifierT extends Record<PropertyKey, PropertyKey>> =
    IdentifierT
;

type Bar<IdentifierT extends Record<PropertyKey, PropertyKey>, T> =
    {
        [k in keyof T] : Foo<IdentifierT & { k : k }>
    }
;

type Merge2<T> = { [k in keyof T] : T[k] }
type Bar2<IdentifierT extends Record<PropertyKey, PropertyKey>, T> =
    {
        [k in keyof T]: Foo<Merge2<IdentifierT & { k: k }>>
        //                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //                  Works in 3.5.1
        //                  Works in 3.6.3
        //                  Works in 3.7.5
        //                  Fails in 3.8.3
    }
;

type Identity<T> = T;
type Merge3<T> = Identity<{ [k in keyof T] : T[k] }>
type Bar3<IdentifierT extends Record<PropertyKey, PropertyKey>, T> =
    {
        [k in keyof T]: Foo<Merge3<IdentifierT & { k: k }>>
        //                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //                  Works in 3.5.1
        //                  Works in 3.6.3
        //                  Works in 3.7.5
        //                  Fails in 3.8.3
    }
;

Expected behavior:

Passes type checking

Actual behavior:

Fails in TS 3.8.3

Playground Link:

Playground

Related Issues:

Not that I could find


Well, it isn't exactly a "no-op" mapped type.

It will strip call and constructor signatures, but "no-op mapped type" was the best name I had for it.

@phiresky
Copy link

phiresky commented May 16, 2020

I think I have the same issue with https://github.com/phiresky/ts-typed-sql, which destroys type inference everywhere, means our whole project is stuck on 3.7 for now :(

@AnyhowStep
Copy link
Contributor Author

I've been stuck at 3.5.1 forever now =(

@phiresky
Copy link

I just bisected the ts compiler to find the cause using

build.sh

#!/bin/bash
set -e -x
bisect_error=125

yarn install --silent || exit $bisect_error
gulp -L local || exit $bisect_error

node built/local/tsc.js --noEmit ../example.ts
git bisect start v3.8.3 v3.7.5
git bisect run ../build.sh

bisect reports:

first bad commit: [357f715] Check combined intersection properties against target index signatures (#35143) by @ahejlsberg

@ahejlsberg
Copy link
Member

A simpler repro for this issue:

type Same<T> = { [P in keyof T]: T[P] };

type Foo<T extends Record<PropertyKey, number>> = T;

type Bar<T extends Record<PropertyKey, number>> = Foo<Same<T>>;  // Error

We shouldn't error above and strangely we don't if the declaration of Foo is changed to

type Foo<T extends Record<string, number>> = T;

That's definitely a bug.

The example above worked before #35143 because we were very lax in our checking of relations involving intersections on the source side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants