Skip to content

Generic computed properties #29259

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
NiGhTTraX opened this issue Jan 4, 2019 · 7 comments
Closed

Generic computed properties #29259

NiGhTTraX opened this issue Jan 4, 2019 · 7 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@NiGhTTraX
Copy link

TypeScript Version: [email protected]

Search Terms: generic computed properties

Code

type withKey<K> = {
    [K]: boolean
}

const X: withKey<'foo'> = {
    foo: true
}

Expected behavior:

I want to be able to type objects that expect a certain key known at compile time. This is useful when writing methods that connect a data source to let's say a React view e.g.

connectToApi(View, API, 'prop')
// 'prop' should be in the interface of `View`

Actual behavior:

Compiler fails with:

A computed property name in a type literal must refer to an expression
whose type is a literal type or a 'unique symbol' type.

Playground Link: https://agentcooper.github.io/typescript-play/#code/C4TwDgpgBA7glsAFgaQiAPMgfFAvFAbwCgpSoBtZAXQC4oAjAe0YBsIBDAOyIF8iiAxo04BnYFAAadeElQYA5ADNm8nPmJkoyxnWAAnAK4Re-IaPEBNaQhRp0SlWsIky9dnt2HjfIA

Related Issues: Don't know if this is related #13948

@jack-williams
Copy link
Collaborator

Maybe?

type withKey<K extends string> = Record<K, boolean>

@gigobyte
Copy link
Contributor

gigobyte commented Jan 4, 2019

This is already possible:

type withKey<K extends string | number | symbol> = {
    [k in K]: boolean
}

@weswigham weswigham added the Question An issue which isn't directly actionable in code label Jan 4, 2019
@NiGhTTraX
Copy link
Author

Perfect, thank you very much!

@scorpevans
Copy link

scorpevans commented Jun 25, 2020

@gigobyte any idea why your example doesn't work if the K part is inferred as follows:

abstract class Message<T extends string> {}
type MessageString<T> = T extends Message<infer S> ? S : never

type WithKey<M> = {
    [m in MessageString<M>]: boolean
}

class M1 extends Message<'M1'>{}
class C1 implements WithKey<M1>{}   // ISSUE: 'M1' property is not enforced here

@scorpevans
Copy link

I figured out that the issue has to do with the inference being made to String as opposed to a Literal; hardcodedly inferring the correct literal type fixes the issue:

abstract class Message<T extends string> {}
type MessageString<T> = T extends Message<infer S> ? 'M1' : never   // infer 'M1' instead of string

type WithKey<M> = {
    [m in MessageString<M>]: boolean
}

class Base {[index:string]: boolean }
class M1 extends Message<'M1'>{}
class C1 extends Base implements WithKey<M1>{}   // NON-ISSUE: 'M1' property is enforced here

The question now is how does one arrange for a literal inference?
related issue: #27704

@scorpevans
Copy link

Resolution:

abstract class Message<T extends string> {}
type MessageString<T> = T extends Message<infer S> ? S : never

type WithKey<M> = {
    [m in MessageString<M>]: boolean
}

class Base {[index:string]: boolean }
//class M1 extends Message<'M1'>{}
type M1 = Message<'M1'>                          // use a *simple* type; no union or intersection
class C1 extends Base implements WithKey<M1>{}   // NON-ISSUE: 'M1' property is enforced here

@aminya
Copy link

aminya commented Apr 16, 2021

I also found a trick to merge multiple generic computed parameters together. It doesn't seem that I can put multiple of these [k1 in Key1]: string in one type, so I had to use &

type Prop1<Key1 extends string> = {
  [k1 in Key1]: string
}
type Prop2<Key2 extends string> = {
  [k2 in Key2]: boolean
}
type MyType<Key1 extends string, Key2 extends string> = Prop1<Key1> & Prop2<Key2>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

6 participants