Skip to content

TS 4.1+ Key remapping in mapped types allows bypassing statically known members check #43189

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
Gerrit0 opened this issue Mar 11, 2021 · 6 comments · Fixed by #52070
Closed
Labels
Bug A bug in TypeScript
Milestone

Comments

@Gerrit0
Copy link
Contributor

Gerrit0 commented Mar 11, 2021

Bug Report

🔎 Search Terms

key remapping static member, arbitrary interface keys, bypassing interface dynamic member check

🕗 Version & Regression Information

With the key remapping introduced in TS 4.1 for mapped types, the following error can be bypassed:

An interface can only extend an object type or intersection of object types with statically known members. (2312)

I was unable to test this on prior versions because key remapping didn't exist.

⏯ Playground Link

💻 Code

// @ts-expect-error -- this isn't allowed
interface RecordInterface<K extends keyof any, V> extends Record<K, V> { }

type RemapRecord<K extends keyof any, V> = { [_ in never as K]: V }

// @ts-expect-error -- but this is!
interface RecordInterface<K extends keyof any, V> extends RemapRecord<K, V> { }

🙁 Actual behavior

TypeScript inconsistently prevents using interfaces with dynamic members.

🙂 Expected behavior

Either RecordInterface to have an error, or to be able to replace Record1 with Record without any error.

CC: @tjjfvi, who discovered this, but hasn't submitted a bug.

There is a feature request (#41383) about changing the definition of Pick which includes a comment about this.

@tjjfvi
Copy link
Contributor

tjjfvi commented Mar 11, 2021

Seems like a feature to me 🤷

@MartinJohns
Copy link
Contributor

I'm confused what in never is even supposed to be.

When hovering over RemapRecord<> the tooltip shows that it maps to {}, so it's an empty interface and a result assignable to any other type.

When mapping it to another type and providing type arguments, e.g. type Foo = RemapRecord<...>, then the type Foo has properties.

@tjjfvi
Copy link
Contributor

tjjfvi commented Mar 11, 2021

My version uses [_ in "" as K]. Apparently the in never also works, but that seems like a separate bug?

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Mar 11, 2021
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Mar 11, 2021
@RyanCavanaugh
Copy link
Member

Please don't take a production dependency on this; I have no idea what might be hiddenly broken when that type starts getting used.

@crowlKats
Copy link

it would be great if this was an actual feature. "dynamically" adding typings would be great in some scenarios

@tjjfvi
Copy link
Contributor

tjjfvi commented Mar 15, 2021

Please don't take a production dependency on this; I have no idea what might be hiddenly broken when that type starts getting used.

👍 ; thinking back now, I remember having some really cryptic bugs that were fixed when I stopped using this behavior

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
5 participants