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 — Variant accessors by RyanCavanaugh · Pull Request #42425 · microsoft/TypeScript

Conversation

@RyanCavanaugh

@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) commented Jan 20, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Getter / Setter Variation

Implements #2845 and #2521

Overview

This implements two related features:

  • The ability to have getter and setter pairs differ in their visibility modifiers (Different access modifier for getter and setter #2845, [feature] class properties that are "readonly in public, writable in private" or other permutations #37487 but not for fields)
  • The ability to have getter and setter pairs differ in their types (Suggestion: allow get/set accessors to be of different types #2521)

Differing Types

Property getters and setters may now differ in their types:

const thing = {
    _size: 0,
    get size(): number {
        return this._size;
    },
    set size(value: string | number) {
        this._size = typeof value === 'string' ? parseInt(value) : value;
    }
}

// OK
thing.size = "100ish";
// OK
console.log(thing.size.toFixed(2));

Restrictions

As a conservative implementation, a few restrictions are in place.

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.

This restriction closes off a certain set of use cases for properties that start out "uninitialized" (usually null/undefined) but then only want "initalizing" assignments to occur. We'll continue to examine these to see if those use cases are prevelant enough to warrant opening this up more.

These prevent novel unsoundness from occurring and makes this feature unimpactful from a type relational perspective, which limits its risk.

Differing Visibility

In classes, set accessors may now be less visible than their corresponding get accessor. It looks like this:

class MyClass {
    get size(): number {
        // TODO: implement
        return 0;
    }
    protected set size(value: number) {
        // TODO: implement
    }

    grow() {
        // OK
        this.size++;
    }
}

let c = new MyClass();
// Error, can't write to 'size' outside of 'MyClass'
c.size = 10;
// OK
console.log(c.size);

Type Relationship Effects

TL;DR: there are none

TypeScript is already covariant when relating properties of types. The unsoundness of this is straightforward to demonstrate during aliased writes:

type Alpha = { x: string | number };
type Beta = { x: string };

function mutate(ref: Alpha) {
    ref.x = 0;
}
const p: Beta = { x: "hello" };
mutate(p);
// Prints 'number' on a binding typed as 'string', oops.
console.log(typeof p.x);

TypeScript also already ignores the readonly modifier when relating types, so the protected or private state of a setter does follows the same pattern.

Caveats

TL;DR: The type system remains entirely covariant in other operations! This has some effects that may not be immediately apparent.

Types with variant getters/setters are effectively reduced to their get side when put through mapped types:

// Setter types are intentionally not preserved
// through mapped types or other transforms; they
// are specific to their originating declaration
declare const CoercingThing: {
    get size(): number;
    set size(v: number | string);
}
type PCT = Partial<typeof CoercingThing>;
declare const pct: PCT;
// Not OK
pct.size = "hello";

This is fairly straightforward to reason about -- a mapped type usually represents a "copy with transform" operation, e.g.

(psuedocode: some type operation f applied to an object type obj)
result = { }
for k in keyof obj
  result[k] = f(obj[k]);
return result

In other words, for an arbitrary mapped type, we have no idea how its actual value is produced, and the only sound assumption is that this type doesn't copy over any coercing semantics from its setters.

The same applies to lookup types -- the type T[K] still means *the read type of K on T. A free setter function can't be used to indirectly access the coercing side of the setter:

declare const CoercingThing: {
    get size(): number;
    set size(v: number | string);
}
function setter<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
    obj[key] = value;
}
// Not OK, even though CoercingThing.size = "100" is OK
setter(CoercingThing, "size", "100");

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

alexrock, raveclassic, LastDragon-ru, ExE-Boss, Griffork, disjukr, paul-marechal, justinfagnani, trusktr, bschlenk, and 34 more reacted with thumbs up emoji ExE-Boss, Griffork, trusktr, bschlenk, xaviergonz, molisani, jorroll, eholman, shicks, GCastilho, and 15 more reacted with hooray emoji chriskrycho, a11delavar, ryall, JavierCane, Nerlin, buschtoens, Seebiscuit, lreading, and source144 reacted with heart emoji ExE-Boss, Griffork, trusktr, xaviergonz, jorroll, whzx5byb, brainkim, Gabriele-Tomberli, a11delavar, AlexAegis, and 5 more reacted with rocket emoji
All reactions
  • 👍 44 reactions
  • 🎉 25 reactions
  • ❤️ 9 reactions
  • 🚀 15 reactions
@typescript-bot TypeScript Bot (typescript-bot) assigned Ryan Cavanaugh (RyanCavanaugh) Jan 20, 2021
@typescript-bot TypeScript Bot (typescript-bot) added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Jan 20, 2021
@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented Jan 20, 2021

Copy link
Copy Markdown
Member Author

TypeScript Bot (@typescript-bot) pack this

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 20, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Ryan Cavanaugh (@RyanCavanaugh), I've started to run the tarball bundle task on this PR at 6f09705. You can monitor the build here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 20, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Hey Ryan Cavanaugh (@RyanCavanaugh), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/93799/artifacts?artifactName=tgz&fileId=3EC3DF89823D37BAFB0102D05E0C5878E1CC64D470DA739FA701667C9C8CEEC602&fileName=/typescript-4.2.0-insiders.20210120.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented Jan 29, 2021

Copy link
Copy Markdown
Member Author

TypeScript Bot (@typescript-bot) pack this

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 29, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Ryan Cavanaugh (@RyanCavanaugh), I've started to run the tarball bundle task on this PR at d2affa2. You can monitor the build here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 29, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Hey Ryan Cavanaugh (@RyanCavanaugh), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/94491/artifacts?artifactName=tgz&fileId=5D2DE7C1D3D1A47BE543A3A8978BBC0D64E3E7103505294FB8EDC8B577A31AA302&fileName=/typescript-4.2.0-insiders.20210129.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) changed the title [Draft] Variant accessors Variant accessors Feb 3, 2021
@RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) marked this pull request as ready for review February 3, 2021 20:31
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request Feb 4, 2021
Design Meeting Notes, 2/3/2021 #42631
Closed
@ExE-Boss

ExE Boss (ExE-Boss) commented Feb 5, 2021

Copy link
Copy Markdown
Contributor

This probably also fixes #32821

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request Feb 11, 2021
TypeScript 4.3 Iteration Plan #42762
Closed
@kylehalleman Kyle Halleman (kylehalleman) mentioned this pull request Feb 17, 2021
[@types/node] Wrong type for ProcessEnv DefinitelyTyped/DefinitelyTyped#51273
Closed
7 of 8 tasks
@trusktr

Joe Pea (trusktr) commented Feb 17, 2021

Copy link
Copy Markdown
Contributor

What milestone will this go into?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Joe Pea (trusktr) added a commit to lume/lume that referenced this pull request Feb 17, 2021
@trusktr
breaking: update types of accessors in preparation for the upcoming v…
687c573
…ariant accessor types in TypeScript

This make accessors have the correct types to represent all possible values that they can be set to, but the getters are funky because to use them it requires type casting. As a temporary workaround, `get*()` methods have been added (f.e. `element.getPosition()` returns the same as `element.position` but with the value casted to the underlying object type.

This does not impact JavaScript users. They can continue to do things like `element.position.x = 123`. But TypeScript users can't do that. They would have to write `;(element.position as XYZNumberValues).x = 123` which is cumbersome, but the temporary getter methods allow TypeScript users to write `element.getPosition().x = 123` instead. TypeScript users can still set values as usual: `this.position = [1, 2, 3]` just like JavaScript users.

The upcoming changes in microsoft/TypeScript#42425 will allow us to update the getter types so TypeScript users can write `element.position.x = 123`.
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request Mar 4, 2021
Image element src property does not allow URL assignment #43066
Open
@RyanCavanaugh
Allow accessors to have different access modifiers and types
b7f93bb
Fixes microsoft#2845, microsoft#2521
@RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) force-pushed the variantAccessors branch from d2affa2 to b7f93bb Compare March 24, 2021 23:58
@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented Mar 25, 2021

Copy link
Copy Markdown
Member Author

TypeScript Bot (@typescript-bot) pack this

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 25, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Ryan Cavanaugh (@RyanCavanaugh), I've started to run the tarball bundle task on this PR at b7f93bb. You can monitor the build here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 25, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Hey Ryan Cavanaugh (@RyanCavanaugh), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/99188/artifacts?artifactName=tgz&fileId=8A4F5CF4310E72AE3F3599DB677A807009BC386229856DAD4B06C74D77071B7702&fileName=/typescript-4.3.0-insiders.20210325.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Mar 25, 2021
Suggestion: allow get/set accessors to be of different types #2521
Closed
Different access modifier for getter and setter #2845
Closed
Ryan Cavanaugh (RyanCavanaugh) added 5 commits March 26, 2021 13:06
@RyanCavanaugh
Error if an accessor body appears in a type context
04170ad
@RyanCavanaugh
Merge branch 'master' into variantAccessors
ed8cd99
# Conflicts:
#	src/compiler/checker.ts
#	src/compiler/diagnosticMessages.json
#	tests/baselines/reference/privateNamesAndGenericClasses-2.errors.txt
@RyanCavanaugh
Fix indent
8086a03
@RyanCavanaugh
Remove stray debugger statement
0e527c0
@RyanCavanaugh
Fix stray error in tst
b4c8ff6
@MartinJohns Martin Johns (MartinJohns) mentioned this pull request Mar 29, 2021
Should getters still infer the same type from setters over their return expressions? #43414
Closed
@RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) deleted the variantAccessors branch March 29, 2021 16:02
Lucas Garron (lgarron) added a commit to cubing/cubing.js that referenced this pull request Apr 3, 2021
@lgarron
[twisty] Remove warning for setting TwistyPlayer alg using string.
72249a6
This will depend on microsoft/TypeScript#42425 landing in stable TypeScript so we can update the types to reflect it.
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request Apr 7, 2021
Design Meeting Notes, 3/26/2021 #43581
Closed
@saschanaz Kagami Sascha Rosylight (saschanaz) mentioned this pull request Apr 13, 2021
Allow setter type to be incompatible with the getter type #43662
Closed
5 tasks done
@kevinclarkadstech

Kevin (kevinclarkadstech) commented Apr 14, 2021

Copy link
Copy Markdown

TypeScript Bot (@typescript-bot) pack this

andrewbranch reacted with eyes emoji
All reactions
  • 👀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@thw0rted James Bromwell (thw0rted) mentioned this pull request Apr 15, 2021
CallbackProperty and positions CesiumGS/cesium#8944
Closed
@peterblazejewicz Piotr Błażejewicz (Peter Blazejewicz) (peterblazejewicz) mentioned this pull request Apr 20, 2021
[@types/node] Fix ProcessEnv DefinitelyTyped/DefinitelyTyped#52467
Closed
7 tasks done
@pikax

Carlos Rodrigues (pikax) commented Apr 26, 2021

Copy link
Copy Markdown

What's the syntax (if supported) for generic types?

Simplified Example:

type MarkAsString<T extends Record<string, any>> = {
    [K in keyof T]: T extends number ? T[K] /* How to set add a string|number set here? */ : T[K]
}

declare const a: MarkAsString<{ a: boolean, b: number, c: string }>
a.b = '42'; // I want to have this avalible

a.c = '112'

// @ts-expect-error
a.a = '2'

Actual use case

In Vue3 there's Ref<T> (simplified as { value: T}) and Reactive<UnwrappedRef<T>> (unwraps {value: T} to T, recursive)
Basically:

const r = ref({ a: 1} )

r.value.a = 1

const a = reactive(r)
a.a // 1

On a reactive/ref object the set in typescript must be UnwrappedRef<T> which is not true, because when you assign to a reactive it will unwrap the value:

const r = ref({a:1});
const a = ref({
  r
}) // results in `{ r: { a: 1 } }` 

a.r = r; // typescript error  because `r` is `Ref<T>` instead of `UnwrappedRef<T>`, but it works at runtime.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@thw0rted

James Bromwell (thw0rted) commented Apr 26, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

I think what you're actually looking for is how to use the new feature with index signatures. My first guess would have been something like

interface ConvertingRecord {
  get [k: string](): string;
  set [k: string](val: string | number);
}

but that doesn't work on the latest Playground for this build. Maybe it's not currently possible?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented Apr 26, 2021

Copy link
Copy Markdown
Member Author

Yeah, that's a totally separate and additional feature.

thw0rted, pikax, and ExE-Boss reacted with thumbs up emoji
All reactions
  • 👍 3 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@pikax

Carlos Rodrigues (pikax) commented Apr 26, 2021

Copy link
Copy Markdown

Yeah, that's a totally separate and additional feature.

Cool, should I open an issue?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented Apr 26, 2021

Copy link
Copy Markdown
Member Author

Sure

pikax, ExE-Boss, and dfidalg0 reacted with thumbs up emoji
All reactions
  • 👍 3 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@pikax Carlos Rodrigues (pikax) mentioned this pull request Apr 26, 2021
Variant accessors for index signatures and mapped types #43826
Open
5 tasks done
@fedeci Federico Ciardi (fedeci) mentioned this pull request May 4, 2021
fix(ts): raise TSError for class accessors with discarding accessibility babel/babel#13250
Closed
@V1raNi

Dmitry Shamshurin (V1raNi) commented Aug 4, 2021

Copy link
Copy Markdown

This is very cool, is there any information on which version will have this change?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@yume-chan

Simon Chan (yume-chan) commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Dmitry Shamshurin (@V1raNi) This has been shipped in 4.3 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-3.html#separate-write-types-on-properties

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ws93

Wei (ws93) commented Aug 7, 2021

Copy link
Copy Markdown

The different type for setter doesn't work for Union type as well. Is this expected? Example can be found here

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@thw0rted James Bromwell (thw0rted) mentioned this pull request Aug 9, 2021
Union of variant setters uses getter type for assignment #45376
Closed
@thw0rted

James Bromwell (thw0rted) commented Aug 9, 2021

Copy link
Copy Markdown

Wei (@ws93) I didn't see an issue for that yet so I went ahead and opened #45376 .

ws93 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@V1raNi

Dmitry Shamshurin (V1raNi) commented Aug 11, 2021

Copy link
Copy Markdown

Dmitry Shamshurin (@V1raNi) This has been shipped in 4.3 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-3.html#separate-write-types-on-properties

Oh, thank you very much. It's just I was interested in different visibility and couldn't find it in the text, and the docs seem to be outdated a bit regarding this part.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@thesayyn Sahin Yort (thesayyn) mentioned this pull request Aug 31, 2021
Fields can be undefined but return type of getters can't thesayyn/protoc-gen-ts#80
Open
@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) mentioned this pull request Dec 15, 2021
Correctly check computed property names in type-space get/set accessors #47156
Merged
@yoursunny Junxiao Shi (yoursunny) mentioned this pull request Jan 13, 2022
Getter and setter accessors do not agree in visibility. yoursunny/NDNts#8
Closed
@killerdbob Huang, Wei (killerdbob) mentioned this pull request Jan 13, 2022
Getter and setter accessors do not agree in visibility. pulsejet/svchat#1
Open
@graynorton Gray Norton (graynorton) mentioned this pull request Aug 24, 2022
<input> value and other properties should accept more types runem/lit-analyzer#43
Open
@jledentu Jérémie Ledentu (jledentu) mentioned this pull request Oct 20, 2022
#628@patch: Handle style setter in HTMLElement. capricorn86/happy-dom#629
Merged
@foxcaulfield Maxim R (foxcaulfield) mentioned this pull request May 11, 2024
Classes.md: Update description for getter and setter member visibility microsoft/TypeScript-Website#3097
Merged
@filipi87 Filipi da Silva Fuchter (filipi87) mentioned this pull request Aug 28, 2024
Fixing couple of warnings and making sandbox work directly with staging. pipecat-ai/pipecat-client-web#57
Closed
@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@sandersn Nathan Shively-Sanders (sandersn) sandersn approved these changes
@ahejlsberg Anders Hejlsberg (ahejlsberg) ahejlsberg left review comments
@andrewbranch Andrew Branch (andrewbranch) andrewbranch approved these changes
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Awaiting requested review from DanielRosenwasser

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh)

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

PR Backlog
Archived in project

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

13 participants

@RyanCavanaugh @typescript-bot @ExE-Boss @trusktr @kevinclarkadstech @pikax @thw0rted @V1raNi @yume-chan @ws93 @sandersn @andrewbranch @ahejlsberg
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.