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 get setter types (because now they can be different than getter types). #43729

Closed
5 tasks done
trusktr opened this issue Apr 19, 2021 · 4 comments
Closed
5 tasks done
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 Apr 19, 2021

⭐ Suggestion

Now that TS 4.3 introduces the awesome ability to have setter types be a different type than getters, it would be useful to be able to get the type of a setter or getter (not just the property as a whole, which defaults to the type of the getter).

🔍 Search Terms

typescript 4.3 get type of setter

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

📃 Motivating Example

Basically this example shows the issue:

class Foo {
  foo = 123

  _bar: any
  get bar(): number { return this._bar }
  set bar(v: number | string | boolean) { this._bar = Number(v) }

  baz = 'baz'

  set(props: Partial<this>) {
    Object.assign(this, props)
    return this
  }
}

const f = new Foo

const props = {
  foo: 2,
  bar: '123',
  baz: 'blah'
}

f.set(props) // Type error.

console.log(f.foo, f.bar, f.baz) // but it works great at runtime

playground

💻 Use Cases

It is currently possible to achieve the desired effect by manually setting the types of the props object, but this is more cumbersome, especially when there are many types. I.e., the burden is on the end user instead of the class author (class author can serve many, instead of end users all having to write type defs).

Here's an example of that. The end user of the class as any as number, which is not ideal.

Ideally the class author would be able to write the set method with setter types, something like:

  set(props: Partial<setters this>) {
    Object.assign(this, props)
    return this
  }

I don't know what the syntax would be, but the idea is that the result of setters this is a type that has the types of the setters for properties that are originally accessors. The other properties works the same as usual.

Or maybe we need types like get this['foo'] and set this['foo'] that can return the getter or setter type of a specific property, and then one can create a mapped type that can use the get or set type operators.

@trusktr
Copy link
Contributor Author

trusktr commented Apr 19, 2021

Or, in other words, based on structural typing, { foo: number, bar: string | number | boolean, baz: string } is technically assignable to { foo: number, bar: string, baz: string }.

Maybe the assignability test needs to look at setter types under the hood? This would make it work without adding a syntax addition.

It seems that really we only care about the getter type when we're getting the value.

So the assignability check would need to use setter types of the destination object, or getter types of the source object.

F.e. in Object.assign(destination, source) or destination = source, the type of source should use getter types, while the types of destination should use setter types.

@justinweinberg
Copy link

To add my use case, I would like consumers of my class to be able to assign a setter with a value T or a function that returns a value T, and the on the getter return T (evaluate the function as needed).

The motivation is to:

  • provide more wrist friendly assignments when the function syntax isn't needed.
  • provide a more intuitive result from the getter than () => T
  • setup chains of dependent properties for lazy evaluation and/or revaluation on each evaluation e.g._baz = () => this.bar
class Foo {

    constructor(spec?:  Partial<Foo>) {
        Object.assign(this, spec);
    }

    _bar : string | (() => string) = ''
    public get bar(): string {
       if (typeof this._bar === 'function') {
           return this._bar();
       }
       return this._bar;     
    }
    
    public set bar(value: string | (() => string)) {
       this._bar = value;
    }

}

//Using assignment with string is fine 
let foo = new Foo();
foo.bar = "Hello";  
console.log(`string assigned setter evaluates to${foo.bar}`)
//Using assignment with function is fine
foo.bar = () => "Hello";  
console.log(`function assigned setter evaluates as ${foo.bar}`)


//Using Partial<T> with value as string is fine
let foo2 = new Foo({bar: "Hello"}); 
console.log(`partial assignment of setter to string results in ${foo2.bar}`)

//Using Partial<T> with () => string gives a type error
let foo3 = new Foo({bar: () => "Hello"} ); //compiler complains unless I force type with 'as any'.   
console.log(`Partial assignment if setter with function results in ${foo3.bar}`)

example

@maxpatiiuk
Copy link

Another use case:
In my web component library, TypeScript emits a .d.ts file for the component class - the class may contain getters and setters of different types.

Based on this component class type, I wish to define the typings for my library for React JSX, Preact JSX and other JSX libraries.

However, when I use TypeScript's mapped type syntax, or Pick<>/Omit<>, I am only able to retrieve the getter types.
For JSX typing, I care only about the setter types.

@trusktr
Copy link
Contributor Author

trusktr commented Oct 8, 2024

@trusktr trusktr closed this as completed Oct 8, 2024
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

4 participants