GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Suggestion: allow get/set accessors to be of different types · Issue #2521 · microsoft/TypeScript

Suggestion: allow get/set accessors to be of different types #2521

New issue
Copy link
New issue
Copy link
Closed
Closed
Suggestion: allow get/set accessors to be of different types#2521
Copy link
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript

Description

@irakliy81
Irakliy (irakliy81)
opened on Mar 26, 2015
Issue body actions

It would be great if there was a way to relax the current constraint of requiring get/set accessors to have the same type. this would be helpful in a situation like this:

class MyClass {

    private _myDate: moment.Moment;

    get myDate(): moment.Moment {
        return this._myDate;
    }

    set myDate(value: Date | moment.Moment) {
        this._myDate = moment(value);
    }
}

Currently, this does not seems to be possible, and I have to resort to something like this:

class MyClass {

    private _myDate: moment.Moment;

    get myDate(): moment.Moment {
        return this._myDate;
    }

    set myDate(value: moment.Moment) {
        assert.fail('Setter for myDate is not available. Please use: setMyDate() instead');
    }

    setMyDate(value: Date | moment.Moment) {
        this._myDate = moment(value);
    }
}

This is far from ideal, and the code would be much cleaner if different types would be allowed.

Thanks!

Reacted by Georgii Dolzhykov, James Bromwell, Douglas Henri, JongChan Choi (Rieul), Aron Adler, Ray Suelzer, Justin Lau, Sergei Sergeev, Zheeeng, drakulis and 196 more
Reacted by oxygen
Reacted by Javier Gonzalez, Klemen Oslaj, Seph Reed, Patricio Ezequiel Hondagneu Roig, Juan Pablo de la Torre, Michael Scott Asato Cuthbert, chili, Alexander, Braden Napier, Ivan Babak and 10 more
Reacted by Simon Ostini
Reacted by Klemen Oslaj and Brian Kim

Activity

Next
  1. danquirk commented on Mar 26, 2015

    @danquirk
    Dan Quirk (danquirk)
    on Mar 26, 2015
    Member
    More actions

    I can see how this would be nice here (and this has been requested before although I can't find the issue now) but it's not possible whether or not the utility is enough to warrant it. The problem is that accessors are not surfaced in .d.ts any differently than normal properties since they appear the same from that perspective. Meaning there's no differentiation between the getter and setter so there's no way to a) require an implementation use an accessor rather than a single instance member and b) specify the difference in types between the getter and setter.

    Reacted by Stefan Bauer, Seph Reed, Jakub Kisielewski, Michael Burkman, oxygen, LvChengbin, Helmut Hummel and Christopher Carman
    Reacted by Clint Pamperin, David Rohmer, Sergey Linnik, Meithal, Krzysztof Kotowicz, Alpvax, Telokis, Joe Pea, Klemen Oslaj, Keegan Farley and 37 more
    Reacted by oxygen
    Reacted by oxygen
    Reacted by oxygen
  2. Dan Quirk (danquirk)
    closed this as completedon Mar 26, 2015
  3. Dan Quirk (danquirk)
    added
    By DesignDeprecated - use "Working as Intended" or "Design Limitation" insteadDeprecated - use "Working as Intended" or "Design Limitation" instead
    on Mar 26, 2015
  4. irakliy81 commented on Mar 27, 2015

    @irakliy81
    Irakliy (irakliy81)
    on Mar 27, 2015
    Author
    More actions

    Thank you for the quick reply, Dan. I'll follow the less elegant way. Thanks for the great work!

  5. tkrotoff commented on Jun 11, 2015

    @tkrotoff
    Tanguy Krotoff (tkrotoff)
    on Jun 11, 2015
    More actions

    A JavaScript getter and setter with different types is perfectly valid and works great and I believe it is this feature's main advantage/purpose. Having to provide a setMyDate() just to please TypeScript ruins it.

    Think also about pure JS libraries that will follow this pattern: the .d.ts will have to expose an union or any.

    The problem is that accessors are not surfaced in .d.ts any differently than normal properties

    Then this limitation should be fixed and this issue should stay open:

    // MyClass.d.ts
    
    // Instead of generating:
    declare class MyClass {
      myDate: moment.Moment;
    }
    
    // Should generate:
    declare class MyClass {
      get myDate(): moment.Moment;
      set myDate(value: Date | moment.Moment);
    }
    
    // Or shorter syntax:
    declare class MyClass {
      myDate: (get: moment.Moment, set: Date | moment.Moment);
      // and 'fooBar: string' being a shorthand for 'fooBar: (get: string, set: string)'
    }
    Reacted by JP de la Torre, Douglas Henri, Lukas, The Reality Engineer, André Gaul, Aron Adler, Justin Lau, Zheeeng, Clint Pamperin, kanatkubash and 76 more
    Reacted by oxygen
    Reacted by oxygen
  6. RyanCavanaugh commented on Jun 11, 2015

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on Jun 11, 2015
    Member
    More actions

    I realize this is just an opinion, but writing a setter such that a.x === y is not true immediately after a.x = y; is a giant red flag. How do consumers of a library like that know which properties have magic side effects and which don't?

    Reacted by Junyoung/"Clare" Jang, Elias Skogevall, Kyrylo Chernyshov, Soroush, Michael Burkman, Felix Becker, JP Denford, Seyi Adebajo, Simon Weaver and chadiik
    Reacted by Julia, Seph Reed, Hopeless Programmer, Khoi Pham, Sahin Yort, Caleb Williams, rzvc and Maxim
    Reacted by Nelson Martell
  7. tkrotoff commented on Jun 11, 2015

    @tkrotoff
    Tanguy Krotoff (tkrotoff)
    on Jun 11, 2015
    More actions

    How do [you] know which properties have magic side effects and which don't?

    In JavaScript it can be un-intuitive, in TypeScript the tools (IDE + compiler) will complain. Why do we love TypeScript again? :)

    Reacted by JP de la Torre, Lukas, Aron Adler, Joe Pea, Sebastian Müller, Michael Scott Asato Cuthbert, Will Stott, Alexey Gerasimov, Anton Bessonov, valepu and 9 more
    Reacted by Elias Skogevall, Jiří Brabec, Seyi Adebajo, Amal Jossy and Toni Tabak
  8. kitsonk commented on Jun 11, 2015

    @kitsonk
    Kitson Kelly (kitsonk)
    on Jun 11, 2015
    Contributor
    More actions

    A JavaScript getter and setter with different types is perfectly valid and works great and I believe it is this feature's main advantage/purpose.

    This is arguing that JavaScript is weakly typed, so TypeScript should be weakly typed. :-S

    Reacted by Junyoung/"Clare" Jang, Michael Burkman, Russell Dempsey and Seyi Adebajo
    Reacted by Peter Flynn, Meithal, Dobes Vandermeer, Joe Pea, Seph Reed, Cyrus Frost, Elias Skogevall, The Reality Engineer, Juan Pablo de la Torre, Will Stott and 13 more
    Reacted by Joe Pea, Elias Skogevall and Eric Ferreira
  9. tkrotoff commented on Jun 11, 2015

    @tkrotoff
    Tanguy Krotoff (tkrotoff)
    on Jun 11, 2015
    More actions

    This is arguing that JavaScript is weakly typed, so TypeScript should be weakly typed

    C# allows it and that does not make this language weakly typed C# does not allow get/set of different types.

  10. kitsonk commented on Jun 12, 2015

    @kitsonk
    Kitson Kelly (kitsonk)
    on Jun 12, 2015
    Contributor
    More actions

    C# allows it and that does not make this language weakly typed C# does not allow get/set of different types.

    😉

  11. paulwalker commented on Oct 21, 2015

    @paulwalker
    Paul Walker (paulwalker)
    on Oct 21, 2015
    More actions

    No one is arguing (as far as I can see) that accessors should be weakly typed, they are arguing that we should have the flexibility to define the type(s).

    Often it is needed to copy a plain old object to object instances.

        get fields(): Field[] {
          return this._fields;
        }
    
        set fields(value: any[]) {
          this._fields = value.map(Field.fromJson);
        }
    

    That is much nicer than the alternative and allows my setter to encapsulate the exact type of logic setters are made for.

    Reacted by JP de la Torre, Douglas Henri, leon, Neil Rackett, jvasoya, Eric Miller, Patricio Ezequiel Hondagneu Roig, Alexander Mills, Chechetkin Ilya, Peter Flynn and 28 more
    Reacted by Joe Pea, Juan Pablo de la Torre and Dillon Redding
    Reacted by Vitória Lopes
  12. danquirk commented on Oct 21, 2015

    @danquirk
    Dan Quirk (danquirk)
    on Oct 21, 2015
    Member
    More actions

    Paul Walker (@paulwalker) the pattern you use there (a setter taking an any and a getter returning a more specific type) is valid today.

    Reacted by a.nvlkv, Juan José Ramírez Calderón, Andrey Sedyshev, Dobes Vandermeer, Keegan Farley, Radovan Bednár, Nkemtakeh Celsoppe and rbehun
  13. paulwalker commented on Oct 21, 2015

    @paulwalker
    Paul Walker (paulwalker)
    on Oct 21, 2015
    More actions

    Dan Quirk (@danquirk) Great to know, thank you! It looks like I just needed to update my IDE plugin compiler for ST.

  14. sccolbert commented on Nov 2, 2015

    @sccolbert
    S. Chris Colbert (sccolbert)
    on Nov 2, 2015
    More actions

    Dan Quirk (@danquirk) That doesn't seem to work according to the playground (or version 1.6.2):
    http://www.typescriptlang.org/Playground#src=%0A%0Aclass%20Foo%20%7B%0A%0A%20%20get%20items()%3A%20string%5B%5D%20%7B%0A%09%20%20return%20%5B%5D%3B%0A%20%20%7D%0A%20%20%0A%20%20set%20items(value%3A%20any)%20%7B%0A%09%20%20%0A%20%20%7D%0A%7D

    Reacted by Joe Pea
  15. jasongrout commented on Nov 2, 2015

    @jasongrout
    Jason Grout (jasongrout)
    on Nov 2, 2015
    More actions

    I just tested with typescript@next (Version 1.8.0-dev.20151102), and also have an error.

    ~$ tsc --version
    message TS6029: Version 1.8.0-dev.20151102
    ~$ cat a.ts
    class A {
        get something(): number {return 5;}
        set something(x: any) {}
    }
    
    ~$ tsc -t es5 a.ts
    a.ts(2,2): error TS2380: 'get' and 'set' accessor must have the same type.
    a.ts(3,2): error TS2380: 'get' and 'set' accessor must have the same type.
    
  16. 150 remaining items

    Load more actions
  17. RyanCavanaugh commented on Mar 25, 2021

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on Mar 25, 2021
    Member
    More actions

    There's a Playground build for PR 42425 available for trying out and I'd appreciate any feedback on how it meets folks' needs here. Thanks! See comments in #42425 on how this works.

    Reacted by gmurray81, somebody1234, Junior Dussouillez, valepu and Jesper van den Ende
    Reacted by Jesper van den Ende
    Reacted by lazytype, whzx5byb, Yann CABON, Juan Pablo de la Torre, GCastilho, valepu and Mateusz Turcza
  18. thw0rted commented on Mar 25, 2021

    @thw0rted
    James Bromwell (thw0rted)
    on Mar 25, 2021
    More actions

    Ryan, is the team planning to refine the DOM defs (in lib.dom.d.ts) if your PR goes through? Is that even possible using the current build process? It'd be a breaking change, but only for code that isn't technically correct (the best kind of correct).

    Reacted by lazytype, Brian Schlenker, Brian Kim, whzx5byb and GCastilho
  19. RyanCavanaugh commented on Mar 25, 2021

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on Mar 25, 2021
    Member
    More actions

    We'll take feedback on the DOM if this goes in. I think we'd still be keeping a pretty tight bar on what's allowed there; most of the DOM has coercing setters where the coercion is in the vein of similarly-disallowed coercions like "5" * "11". More "obvious" coercions like string -> URL seem like the kind of thing we'd be open to.

    Reacted by James Bromwell, ExE Boss and Mateusz Turcza
  20. Ryan Cavanaugh (RyanCavanaugh)
    added a commit that references this issue on Mar 27, 2021

    Variant accessors (#42425)

    ff233a9
  21. hopeless-programmer-online commented on Apr 16, 2021

    @hopeless-programmer-online
    Hopeless Programmer (hopeless-programmer-online)
    on Apr 16, 2021
    More actions

    Any updates?

    In the following code example:

    class vec2 {
      x : number
      y : number
    
      dot(other : vec2) : number
    }
    class vec3 {
      get xy() : vec2
      set xy(xy : { x : number, y : number })
    }

    we are forced to return only { x : number, y : number } on get x() or to accept only vec2 on set x().
    While the ideal approach would be to get fully operable vec2 with all its methods and to set anything that has x and y.

  22. thw0rted commented on Apr 16, 2021

    @thw0rted
    James Bromwell (thw0rted)
    on Apr 16, 2021
    More actions

    In #42425, Ryan said "First, the type of the getter must be assignable to the type of the setter. In other words, the assignment obj.x = obj.x; must be legal assuming obj.x is writable at all.... These prevent novel unsoundness from occurring and makes this feature unimpactful from a type relational perspective, which limits its risk." It sounds like the incoming feature will not support your use case.

    That said, look immediately above your post: #43662 was just opened, which points out that "[Element#style] is one where you can’t just make the set type string | CSSStyleDeclaration because assigning a CSSStyleDeclaration back to the accessor doesn’t work". Maybe follow / upvote that issue and watch for more discussion there?

  23. pckhoi commented on Apr 20, 2021

    @pckhoi
    Khoi Pham (pckhoi)
    on Apr 20, 2021
    More actions

    There is no reason to think that separately typed getter/setter should not be used in a greenfield project. JavaScript isn't statically typed and it has its own benefits: more terse and expressive syntax. Not having to remember 200 different method names that do a single thing with slightly different input is a great thing! This is even more powerful when taking into account new ES features such as proxy. This is just very valuable to library author.

    While we're at it how about adding differently typed getter/setter to interface also? E.g.

    interface SeriesGetter {
      get [prop:string]: Series
      set [prop:string]: number | string | null | undefined | Series
    }

    Only reason why I want this on interface is because this is the only way for proxy to work in typescript.

  24. shicks commented on Apr 20, 2021

    @shicks
    Stephen Hicks (shicks)
    on Apr 20, 2021
    Contributor
    More actions

    In the following code example:

    class vec2 {
      x : number
      y : number
    
      dot(other : vec2) : number
    }
    class vec3 {
      get xy() : vec2
      set xy(xy : { x : number, y : number })
    }

    we are forced to return only { x : number, y : number } on get x() or to accept only vec2 on set x().
    While the ideal approach would be to get fully operable vec2 with all its methods and to set anything that has x and y.

    This already works in the proposed PR. See this example.

    While we're at it how about adding differently typed getter/setter to interface also? E.g.

    interface SeriesGetter {
      get [prop:string]: Series
      set [prop:string]: number | string | null | undefined | Series
    }

    Only reason why I want this on interface is because this is the only way for proxy to work in typescript.

    To be pedantic, it does work on interfaces (see example). What doesn't work is index signatures, which honestly I'm okay with, since it's impossible to write such a getter/setter pair without proxies, and by the time you're talking about proxies, static typing is a bit of a stretch.

    Reacted by Hopeless Programmer
  25. pckhoi commented on Apr 20, 2021

    @pckhoi
    Khoi Pham (pckhoi)
    on Apr 20, 2021
    More actions

    Hey there are value in slapping some typing info onto proxies. Why do we need to be extreme and say either proxy or static typing?

  26. mike-marcacci commented on Apr 20, 2021

    @mike-marcacci
    Mike Marcacci (mike-marcacci)
    on Apr 20, 2021
    More actions

    I am extremely interested in this because it is a prerequisite for my proposal to fix the major soundness issue with index signatures in a way that has a fairly well-considered migration path (if I can say so myself).

    Of course, tracking get/set separately does raise some new questions, especially around type refinement. For example:

    type SomeMap = {
      get [key: string](): string | undefined;
      set [key: string](string): string;
    }
    
    function(map: SomeMap) {
      map.alpha = "beta";
      const { alpha } = map;
      // Here I would expect alpha to be refined to "beta" because
      // we are treating the object as a "map". This follows current
      // refinement rules, and is what I'm interested in.
    }
    
    type Foo =  {
      get alpha(): string | number,
      set alpha(value: string | boolean): string | boolean
    }
    
    function(foo: Foo) {
      foo.alpha = true;
      const { alpha } = foo;
      // What value is foo? We can't really refine our type here...
    }

    While the former scenario is almost certainly the biggest use-case here (and the one I care about), keeping the desired logic breaks the latter; supporting the second case severely limits usefulness of the former without some additional mechanism for describing when these the compiler can make these refinements.

    I think perhaps some additional mechanism for this needs to be drawn up.

  27. thw0rted commented on Apr 20, 2021

    @thw0rted
    James Bromwell (thw0rted)
    on Apr 20, 2021
    More actions

    Mike, you should make a playground example to illustrate what you think is going on. You say that you'd expect const {alpha} to be typed as "beta" (literal) following current refinement rules, but it actually narrows to string.

    From that same Playground, even without the new feature you wind up with unsound / incorrect assumptions about property accessors. This is of course dumb:

    class Bar {
      private _x: string | number = 1;
      get x(): string | number {
        return this._x;
      }
      set x(val: string | number) {
        if (Number.isInteger(val)) {
          this._x = `${val}`;
        } else {
          this._x = Number(val);
        }
      }
    }
    
    const b = new Bar();
    
    b.x = 5
    const x1 = b.x; // number
    console.log(`number? no, ${typeof x1}`); // logs "string"
    
    b.x = "3";
    const x2 = b.x; // string
    console.log(`string? no, ${typeof x2}`); // logs "number"

    but I'm sure there are more reasonable real-world use cases.

  28. pckhoi commented on Apr 20, 2021

    @pckhoi
    Khoi Pham (pckhoi)
    on Apr 20, 2021
    More actions

    I would be happy enough if type refinement simply follow to the letters of what the declaration describe for now. map.alpha can just be string | undefined, foo.alpha can just be string | number.

    Maybe extra fine type refinement can be declared somehow in the future but I think it's out of this issue's scope.

  29. ftzi commented on May 26, 2021

    @ftzi
    Bruno Fantauzzi (ftzi)
    on May 26, 2021
    More actions

    Ryan Cavanaugh (@RyanCavanaugh) Close this? #42425

    Reacted by Ryan Cavanaugh
  30. RyanCavanaugh commented on May 26, 2021

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on May 26, 2021
    Member
    More actions

    Yep. Folks can track #43662 for possible loosening of the get/set relation.

    Reacted by Bruno Fantauzzi and stefnotch
  31. Ryan Cavanaugh (RyanCavanaugh)
    closed this as completedon May 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.