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

Union of Record<string, string> and interface can't be indexed by string #51478

Closed
antonilol opened this issue Nov 10, 2022 · 6 comments
Closed

Comments

@antonilol
Copy link

antonilol commented Nov 10, 2022

Bug Report

πŸ”Ž Search Terms

πŸ•— Version & Regression Information

error on all version ts playground let me choose

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

interface i {
    key: number
}

type t = Record<string, string> | i;

declare let obj: t;
declare let k: string;

// expected type: string | number, actual: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 't'.
//                                           No index signature with a parameter of type 'string' was found on type 't'. (7053)
const v = obj[k];

πŸ™ Actual behavior

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 't'.
  No index signature with a parameter of type 'string' was found on type 't'. (7053)

Record<string, string> | { key: number } can be indexed with string

πŸ™‚ Expected behavior

const v's type was successfully inferred as string | number

@fatcerberus
Copy link

k is an arbitrary string and t may be a value of type { key: number }, which can't be indexed with arbitrary strings. The error is correct.

@fatcerberus
Copy link

It would be wrong to infer string | number here, for the record.

const x = { key: 42, pigz: true }
const k = "pigz";
const obj: t = x;
console.log(obj[k]);  // prints true (a boolean) at runtime.

When you have something typed X | Y it means the value can be either of those types, but you don't know which one. You probably want an intersection type instead.

@antonilol
Copy link
Author

When you have something typed X | Y it means the value can be either of those types, but you don't know which one. You probably want an intersection type instead.

ah you're right, what i want is probably { [k in string]?: k extends 'key' ? number : string }, but it doesn't seem to work.
{ [k in string]?: string } & { key?: number } also doesn't seem to work, in both cases when indexed with string the resulting type is string | undefined, where did the number go?

@fatcerberus
Copy link

Wait, so you're trying to represent a type which is otherwise a Record<string, string> except for a few named properties of a different type? That isn't really supported, because an index signature, when present, is supposed to apply to all properties in an object. If you try to write { [x: string]: string, key: number } you get an error saying that the index signature must match all properties. As you've seen you can bypass that error by using intersection types, but the resulting type breaks the compiler's assumptions, so you basically have undefined behavior.

Based on your use case, this appears to be a duplicate of #15151/#17867.

@antonilol
Copy link
Author

Wait, so you're trying to represent a type which is otherwise a Record<string, string> except for a few named properties of a different type?

yes

Based on your use case, this appears to be a duplicate of #15151/#17867.

thanks for pointing me in the right direction, closing this now

@antonilol antonilol closed this as not planned Won't fix, can't repro, duplicate, stale Nov 14, 2022
@fatcerberus
Copy link

@antonilol In this specific case, if all you care about is getting string | number when using an arbitrary string to index the object, you could just write { [x: string]: string | number, key: number }. That's what TS expects you to write anyway and isn't a problem. The problem is only when you want obj[k] to just be string, which is of course unsound.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants