Skip to content

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

Closed
@AnyhowStep

Description

@AnyhowStep

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.

Activity

phiresky

phiresky commented on May 16, 2020

@phiresky

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

AnyhowStep commented on May 21, 2020

@AnyhowStep
ContributorAuthor

I've been stuck at 3.5.1 forever now =(

phiresky

phiresky commented on May 23, 2020

@phiresky

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

ahejlsberg commented on May 24, 2020

@ahejlsberg
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.

self-assigned this
on May 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

    Participants

    @phiresky@ahejlsberg@AnyhowStep

    Issue actions

      No-op mapped type not assignable; but original type is assignable · Issue #38235 · microsoft/TypeScript