question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SUGGESTION: add support for writeonly properties on interfaces

See original GitHub issue

I’d like to resurrect an old discussion around the desire to have getters/setters support for interfaces: #11878

Obviously we can use readonly to express a property on an interface that has just a getter but there’s no way of expressing that a property should have just a setter. In issue #11878 there was an idea proposed to add the concept of a writeonly property designed to cover this need but the consensus was that there wasn’t enough real-world scenarios to justify such a feature. So let me try and add one.

We have a situation where we have a child object that we want to publish data to a parent but while we want the parent to know about its child we don’t want the child to know about its parent. We’ve ruled out the use of events because we only want a single subscriber and we need to return a Promise to the child to let them know when we’re done. Instead we’ve opted to establish what we would have called a “weak reference” between the child and parent back in the days of COM. The interface in TypeScript looks something like this:

interface Adapter {
     onDataReceived: (data: any) => Promise<void>;
     publishData(data: any): Promise<void>;
}

As you can see data flows bidirectionally between the parent and child and while we’ve received a couple of questions about why the interface is the way it is, it’s generally easy enough to grok from a TypeScript perspective.

The issue we just ran into, however, is that a developer on our team just created a class in ES6 that implements this interface and the result ended up being… yuck 😦

If we literally implement this interface in a declarative way in ES6 it looks something like:

export class WebAdapter {
     get onDataReceived() {
          return this.callback;
     }
     set onDataReceived(cb) {
          this.callback = cb;
     }
     postData(data) {
     }
}

Not only is it crappy that you have to define a getter and a setter, the fact of the matter is we’re never going to ask for the callback back so the getter is pointless here. So what did our dev do? He did this:

export class WebAdapter {
     onDataReceived(data) {
          // will be replaced by parent
     }
     postData(data) {
     }
}

That technically works and what’s nice is you have some sense of the signature of the handler but it makes my skin crawl to look at it. If I was to mirror that in my TypeScript interface you’d have zero clue that onDataReceived() was something I expect you to override. What I really want the developer to have to write implementation wise is this:

export class WebAdapter {
     set onDataReceived(cb) {
          this.callback = cb;
     }
     postData(data) {
     }
}

That’s the proper contract for a weak reference but I have no way of expressing it in TypeScript. While it’s very rare that you need to do this it doesn’t make it any less valid a scenario. The addition of “writeonly” properties would give me a way to express this.

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:47
  • Comments:17 (5 by maintainers)

github_iconTop GitHub Comments

8reactions
dead-claudiacommented, Feb 9, 2019

BTW, this could solve React’s ref invariance issue.

interface ReactRef<T> {
	current: T | void
}

interface ReactRefConsume<T> {
	writeonly current: T
}

interface Attributes {
	ref: ReactRefConsume<HTMLElement>
}

export function createRef<T>(): ReactRef<T>
7reactions
Artazorcommented, Nov 16, 2020

Looks like it could be a reasonable semi-measure that will allow somehow model a covarince/contravariance (that I suppose will never be implemented in TS)

type AnyFunction = (...args: writeonly never[]) => unknown

It’s kinda dangerous, yet looks better than

type AnyFunction = (...args: any[]) => unknown

However, for the full support it should be properly integrated with mapped types. something like this:

type InverseVariance<T> = {
       writeonly [P in readonly T]: T[P];
       readonly [P in writeonly T]: T[P];
}

Just fantasying…

@DanielRosenwasser @Igorbek @isiahmeadows ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Overriding properties and write-only properties (CA1044)
I wrote some interfaces to support a'la indexed properties in C#. The main point is that if I want an indexed property named...
Read more >
vb.net - If an interface defines a ReadOnly Property, how can ...
Now supported in Visual Studio 2015. What's New for Visual Basic. Readonly Interface Properties. You can implement readonly interface properties using a ...
Read more >
Why it is not recommended to have set-only property?
Use the following guidelines to help you choose between these options. Use a property when the ... Read-Only and Write-Only Properties.
Read more >
Read Only And Write Only Automatic Properties In Interface - ADocLib
One use for a writeonly property is to support setter dependency injection.Sources I've read have suggested that if you honestly have a situation....
Read more >
Effective Go - The Go Programming Language
Values; Interfaces and other types: Interfaces: Conversions: Interface ... Note added January, 2022: This document was written for Go's release in 2009, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found