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

Ability to pick setter types (instead of getter types) in a mapped type #60162

Open
5 of 6 tasks
trusktr opened this issue Oct 7, 2024 · 3 comments
Open
5 of 6 tasks
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@trusktr
Copy link
Contributor

trusktr commented Oct 7, 2024

πŸ” Search Terms

typescript extract setter types mapped type

βœ… Viability Checklist

⭐ Suggestion

(original thread on Discord)

This might be a request for a new utility type, or a new language feature, because there seems to be no way to do it with current language features currently:

Given this type:

class Foo {
  get foo(): number {...}
  set foo(v: 'foo' | 'bar' | number) {...}
}

We want to derive a type like this:

type Derived = PickWithSetterTypes<Foo>
// result:
// {foo: 'foo' | 'bar' | number}

There seems to be no way to implement PickWithSetterTypes in userland.

πŸ“ƒ Motivating Example

When writing class-based JSX components (for example, custom elements are written as classes), the JSX property types are setters, not getters.

In this JSX expression:

return <some-element foo={123} />

The foo prop is a setter, and it is setting the property on the custom element, it is not reading the property from the element.

So, when we define a class component, for example:

class SomeElement extends HTMLElement {
  get foo(): number {...}
  set foo(v: 'foo' | 'bar' | number) {...}

  someMethod() {... this method should not be included in JSX types ...}
}

customElements.define('some-element', SomeElement)

We need to pluck the properties that we want available in the JSX. For example, something along the lines of this:

declare module 'some-lib' {
  namespace JSX {
    interface IntrinsicElements {
      'some-element': Pick<SomeElement, 'foo'>
    }
  }
}

Now, the problem is, when we try to set a valid value for the property in JSX, it will not work:

return <some-element
  foo={'foo'} // Type Error: 'foo' is not assignable to number
/>

There should not be a type error, because the setter actually does accept the value 'foo'.

πŸ’» Use Cases

  1. What do you want to use this for?
    • Any situations where the setter types need to be extracted, for example JSX props
  2. What shortcomings exist with current approaches?
    • it is impossible right now
  3. What workarounds are you using in the meantime?
    • Workarounds could include providing separate named properties that can be extracted with template string types, but it is very cumbersome
      class SomeElement extends HTMLElement {
        set foo(v: this['_set_foo']) {...}
        get foo(): number {...}
        
        /** do not use this property, it is for types only */
        _set_foo!: 'foo' | 'bar' | number
      }
      With this method, now a utility type can be written that can use template string types to extract the setter type from the non-setter dummy property type, something like this:
      type SomeElementJSXProps = JSXProps<SomeElement, 'fooBar' | 'foo'> // see linked playground below
      
      declare module 'react' {
          namespace JSX { interface IntrinsicElements { 'my-el': SomeElementJSXProps } }
      }
      TypeScript playground example
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Oct 7, 2024
@trusktr trusktr changed the title Aility to pick setter types (instead of getter types) in a mapped type Ability to pick setter types (instead of getter types) in a mapped type Oct 7, 2024
@MartinJohns
Copy link
Contributor

Isn't this a duplicate of your own #43729?

@trusktr
Copy link
Contributor Author

trusktr commented Oct 8, 2024

Ah yes indeed, I forgot, and search failed. πŸ˜„ This one details the JSX used case better (which was mentioned in #43729 (comment)).

I closed

in favor of this one.

@trusktr
Copy link
Contributor Author

trusktr commented Mar 2, 2025

Is more feedback needed?

I also opened this related issue:

This is one is for mapped types in general, while that one is for fixing the built-in mechanism of how TypeScript reads JSX types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants