Skip to content

Design Meeting Notes, 7/28/2017 #17502

Closed
Closed
@DanielRosenwasser

Description

@DanielRosenwasser

f# Readonly on Exports from Namespaces (#16720)

namespace N {
    export class C { }
}

N.C = class {};
  • Namespaces have had this feature for a while now
    • Breaking changes for something that's functioned that way this long seems strange.
  • Declined

Readonly & Variance

  • One thing that comes up quite a bit is strict variance.

  • If we enabled stricter variance, that would imply that Array becomes invariant.

    • To get a covariant array, you need a ReadonlyArray.
    • This means everything gets two declarations - T and ReadonlyT
  • Strict variance is easy to enable, but would be hard to make easy to use.

  • This leads us to start thinking about how to quickly make a readonly version of a type.

  • We've had an experimental type operator called readonly

    • Much like keyof T, you just write readonly T.
  • Like the Readonly mapped type, it makes all properties readonly as well.

    • However, the Readonly<T> mapped type doesn't eliminate mutating methods at all.
  • This means we needed to add a way to indicate that a method doesn't mutate its object.

    • Created the this: readonly syntax.
  • Example:

    class Foo {
        name: string;
        getName(this: readonly): string;
        setName(value: string): void;
    }
    
    // This:
    type ReadonlyFoo = readonly Foo;
    
    // ... is equivalent to this:
    type ReadonlyFoo = {
        readonly name: string;
        readonly getName(this: readonly): string;
    }
  • What about deep readonly?

    • In other words, does readonly Foo[] give you a readonly Array<readonly Foo>?
    • Have thus far decided no.
      • Could create an immutable type operator
        • Q: Couldn't you implement that with mapped types?
          • A: Potentially
        • May be a bit confusing since state could be captured outside of current object
  • In --strictReadonly mode, this readonly operator would work as described above.

    • readonly T not assignable to T.
    • readonly props would not be assignable to mutable props.
    • readonly T removes mutating methods
  • Outside of strictReadonly, readonly T is just Readonly<T>

  • All of this means that library authors would need to enable readonly mode.

  • Would TypeScript be able to infer whether a method is readonly or not?

    • Kind of tricky, methods transitively call each other.
  • How bad are strict variance modes without this?

    • Special hell for passing callbacks.
    • Need a super constraint for generics - otherwise many types stay invariant by virtue of taking a T as an input position.
  • Will people know how to use this: readonly?

    • Seems like people will always need to be mindful of this when they write .d.ts files.
    • How will we generate this for the DOM if the metadata isn't present? What about readonly HTMLElement?
  • How do this: readonly parameters work with overloads?

    • Currently, if any overloads are not declared with this: readonly, the property is eliminated.
    • That's not going to play well with libraries.
      • Example: Knockout.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design NotesNotes from our design meetings

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions