Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Variant accessors#42425

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged

Conversation

@RyanCavanaugh
Copy link
Member

@RyanCavanaughRyanCavanaugh commentedJan 20, 2021
edited
Loading

Getter / Setter Variation

Implements#2845 and#2521

Overview

This implements two related features:

Differing Types

Property getters and setters may now differ in their types:

constthing={_size:0,getsize():number{returnthis._size;},setsize(value:string|number){this._size=typeofvalue==='string' ?parseInt(value) :value;}}// OKthing.size="100ish";// OKconsole.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 assumingobj.x is writable at all.

This restriction closes off a certain set of use cases for properties that start out "uninitialized" (usuallynull/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 correspondingget accessor. It looks like this:

classMyClass{getsize():number{// TODO: implementreturn0;}protectedsetsize(value:number){// TODO: implement}grow(){// OKthis.size++;}}letc=newMyClass();// Error, can't write to 'size' outside of 'MyClass'c.size=10;// OKconsole.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:

typeAlpha={x:string|number};typeBeta={x:string};functionmutate(ref:Alpha){ref.x=0;}constp:Beta={x:"hello"};mutate(p);// Prints 'number' on a binding typed as 'string', oops.console.log(typeofp.x);

TypeScript also already ignores thereadonly modifier when relating types, so theprotected orprivate 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 theirget side when put through mapped types:

// Setter types are intentionally not preserved// through mapped types or other transforms; they// are specific to their originating declarationdeclareconstCoercingThing:{getsize():number;setsize(v:number|string);}typePCT=Partial<typeofCoercingThing>;declareconstpct:PCT;// Not OKpct.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 typedoesn't copy over any coercing semantics from its setters.

The same applies to lookup types -- the typeT[K] still means *theread type ofK onT. A freesetter function can't be used to indirectly access the coercing side of the setter:

declareconstCoercingThing:{getsize():number;setsize(v:number|string);}functionsetter<T,KextendskeyofT>(obj:T,key:K,value:T[K]){obj[key]=value;}// Not OK, even though CoercingThing.size = "100" is OKsetter(CoercingThing,"size","100");

alexrock, raveclassic, LastDragon-ru, ExE-Boss, Griffork, disjukr, paul-marechal, justinfagnani, trusktr, bschlenk, and 34 more reacted with thumbs up emojiExE-Boss, Griffork, trusktr, bschlenk, xaviergonz, molisani, jorroll, eholman, shicks, GCastilho, and 15 more reacted with hooray emojichriskrycho, a11delavar, ryall, JavierCane, Nerlin, buschtoens, Seebiscuit, lreading, and source144 reacted with heart emojiExE-Boss, Griffork, trusktr, xaviergonz, jorroll, whzx5byb, brainkim, Gabriele-Tomberli, a11delavar, AlexAegis, and 5 more reacted with rocket emoji
@typescript-bottypescript-bot added Author: Team For Uncommitted BugPR for untriaged, rejected, closed or missing bug labelsJan 20, 2021
@RyanCavanaugh
Copy link
MemberAuthor

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commentedJan 20, 2021
edited
Loading

Heya@RyanCavanaugh, I've started to run the tarball bundle task on this PR at6f09705. You can monitor the buildhere.

@typescript-bot
Copy link
Collaborator

typescript-bot commentedJan 20, 2021
edited
Loading

Hey@RyanCavanaugh, I've packed this intoan installable tgz. You can install it for testing by referencing it in yourpackage.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 runningnpm install.


There is also a playgroundfor this build and annpm module you can use via"typescript": "npm:@typescript-deploys/pr-build@4.2.0-pr-42425-2".;

@RyanCavanaugh
Copy link
MemberAuthor

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commentedJan 29, 2021
edited
Loading

Heya@RyanCavanaugh, I've started to run the tarball bundle task on this PR atd2affa2. You can monitor the buildhere.

@typescript-bot
Copy link
Collaborator

typescript-bot commentedJan 29, 2021
edited
Loading

Hey@RyanCavanaugh, I've packed this intoan installable tgz. You can install it for testing by referencing it in yourpackage.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 runningnpm install.


There is also a playgroundfor this build and annpm module you can use via"typescript": "npm:@typescript-deploys/pr-build@4.2.0-pr-42425-5".;

@RyanCavanaughRyanCavanaugh changed the title[Draft] Variant accessorsVariant accessorsFeb 3, 2021
@RyanCavanaughRyanCavanaugh marked this pull request as ready for reviewFebruary 3, 2021 20:31
@ExE-Boss
Copy link
Contributor

This probably also fixes #32821

@trusktr
Copy link
Contributor

What milestone will this go into?

trusktr added a commit to lume/lume that referenced this pull requestFeb 17, 2021
…ariant accessor types in TypeScriptThis 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 inmicrosoft/TypeScript#42425 will allow us to update the getter types so TypeScript users can write `element.position.x = 123`.
@RyanCavanaugh
Copy link
MemberAuthor

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commentedMar 25, 2021
edited
Loading

Heya@RyanCavanaugh, I've started to run the tarball bundle task on this PR atb7f93bb. You can monitor the buildhere.

@typescript-bot
Copy link
Collaborator

typescript-bot commentedMar 25, 2021
edited
Loading

Hey@RyanCavanaugh, I've packed this intoan installable tgz. You can install it for testing by referencing it in yourpackage.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 runningnpm install.


There is also a playgroundfor this build and annpm module you can use via"typescript": "npm:@typescript-deploys/pr-build@4.3.0-pr-42425-10".;

# Conflicts:#src/compiler/checker.ts#src/compiler/diagnosticMessages.json#tests/baselines/reference/privateNamesAndGenericClasses-2.errors.txt
@RyanCavanaughRyanCavanaugh deleted the variantAccessors branchMarch 29, 2021 16:02
lgarron added a commit to cubing/cubing.js that referenced this pull requestApr 3, 2021
This will depend onmicrosoft/TypeScript#42425 landing in stable TypeScript so we can update the types to reflect it.
@kevinclarkadstech
Copy link

@typescript-bot pack this

andrewbranch reacted with eyes emoji

@pikax
Copy link

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

Simplified Example:

typeMarkAsString<TextendsRecord<string,any>>={[KinkeyofT]:Textendsnumber ?T[K]/* How to set add a string|number set here? */ :T[K]}declareconsta:MarkAsString<{a:boolean,b:number,c:string}>a.b='42';// I want to have this avaliblea.c='112'//@ts-expect-errora.a='2'

Actual use case

In Vue3 there'sRef<T> (simplified as{ value: T}) andReactive<UnwrappedRef<T>> (unwraps{value: T} toT, recursive)
Basically:

constr=ref({a:1})r.value.a=1consta=reactive(r)a.a// 1

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

constr=ref({a:1});consta=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.

@thw0rted
Copy link

thw0rted commentedApr 26, 2021
edited
Loading

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?

@RyanCavanaugh
Copy link
MemberAuthor

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

thw0rted, pikax, and ExE-Boss reacted with thumbs up emoji

@pikax
Copy link

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

Cool, should I open an issue?

@RyanCavanaugh
Copy link
MemberAuthor

Sure

pikax, ExE-Boss, and dfidalg0 reacted with thumbs up emoji

@V1raNi
Copy link

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

@yume-chan
Copy link
Contributor

@ws93
Copy link

ws93 commentedAug 7, 2021

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

@thw0rted
Copy link

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

ws93 reacted with thumbs up emoji

@V1raNi
Copy link

@V1raNi This has been shipped in 4.3https://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.

@microsoftmicrosoft locked asresolvedand limited conversation to collaboratorsOct 21, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.

Reviewers

@sandersnsandersnsandersn approved these changes

@ahejlsbergahejlsbergahejlsberg left review comments

@andrewbranchandrewbranchandrewbranch approved these changes

@DanielRosenwasserDanielRosenwasserAwaiting requested review from DanielRosenwasser

Assignees

@RyanCavanaughRyanCavanaugh

Labels

Author: TeamFor Uncommitted BugPR for untriaged, rejected, closed or missing bug

Projects

Archived in project

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

13 participants

@RyanCavanaugh@typescript-bot@ExE-Boss@trusktr@kevinclarkadstech@pikax@thw0rted@V1raNi@yume-chan@ws93@sandersn@andrewbranch@ahejlsberg

[8]ページ先頭

©2009-2025 Movatter.jp