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.

Allow object types to have property-like associated types

See original GitHub issue

Edit: Add static Type variant for classes, make abstractness a little clearer, clarify things.

This has probably already been asked before, but a quick search didn’t turn up anything.

This is similar, and partially inspired by, Swift’s/Rust’s associated types and Scala’s abstract types.


Rationale

  • In complex structures like in virtual DOM components/nodes and in graphs, where there are numerous constraints to check, but they would get cumbersome in a hurry to force off onto the user.
  • In dynamic imports, where you never have the module namespace itself until runtime, yet you still want to be able to use types defined within it. Edit: Already addressed elsewhere.
  • In types where there’s a lot of optional parameters, it’d be easier and more flexible to label which ones you’re defining as part of the type.
  • In types where you want to specify a single optional parameter, and the required ordering requires you to specify some that you don’t want to specify, that would get boilerplatey in a hurry. I’ve experienced this personally on multiple occasions.
  • It would allow fully typing namespaces and named module imports without hard-coded compiler handling.

Proposed Syntax/Semantics

  • Each interface and object type may have a number of associated types within it.
  • Associated types are checked for assignability like any other usual property, except they live in a different “namespace” from properties. In particular, the type must be assignable to the target’s type.
  • To access an associated type, you use TypeName.Type, where Type is the name of an associated type.
    • For sugar and namespace compatibility, object.Type is equivalent to (typeof object).Type
  • To expect an interface with an associated type, you use Foo & {type Type: Value} or Foo with <Type: Value>.
  • To expect an object with an associated type, you use {type Type: Value}.
  • To declare an abstract associated type, you use type Type: * within the interface or object type.
  • To declare a non-abstract associated type, you use type Type: Default within the interface or object type.
  • To constrain an abstract associated type, you use type Type: * extends Super.
  • Associated types may be inherited from other interfaces and/or object types.
  • Namespaces’ types are modified to include the exported types as associated types.
  • Classes may also define associated types, optionally with visibility modifiers.
  • Associated types may have defaults, in case they aren’t defined or further constrained later.
    • Constraining an associated type with an existing default removes the default if and only if the existing constraint is not assignable to the new constraint. For example, {type Foo: string | number = string} & {type Foo: string | number} is assignable to {type Foo: string}, but {type Foo: string | number = string} & {type Foo: number} is not.

Here’s what that would look like in syntax:

// Interfaces
interface Foo {
    type Type: *; // abstract
    type Sub: * extends Type; // abstract, constrained
    type Type: Default;
    type Type: * extends Type = Default; // late-bound default
}

// Objects
type Foo = {
    type Type: Foo,
}

// Classes
abstract class Foo {
    // Note: outer class *must* be abstract for these, and the keyword is required.
    abstract type Type: *; // abstract
    private abstract type Sub: * extends Type; // abstract, constrained
    protected abstract type Type: * extends Type = Default, // late-bound default

    // Note: outer class *may* be not abstract for these.
    type Type: Default;
    private type Type: Default;

    // Declare an associated type in the class
    // Note: type must not be abstract.
    static Type: Foo;
}

Emit

This has no effect on the JavaScript emit as it is purely type-level.

Compatibility

  • This is purely additive, making no observably incompatible changes beyond possibly different error messages.
  • This has no impact on any existing JavaScript-related proposal.

Other

  • It may slow down the type checker a little initially when namespaces are unified, but two optimization points are available, which would recover most of the perf hit, if not all:
    • Associated types could be stored in a per-interface type map.
    • The list of associated types could be initially stored as undefined to avoid generating a large number of empty arrays.
  • It should have little effect on editor tooling.

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:54
  • Comments:34 (12 by maintainers)

github_iconTop GitHub Comments

10reactions
Sajjoncommented, Oct 28, 2020

We NEED this.

10reactions
dead-claudiacommented, Jul 10, 2020

Any status update? Could still totally use this myself for the reasons explained in the initial comment, too.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Understanding protocol associated types and their constraints
In case you're not familiar, Movie and Song conform to Item because Swift structs automatically get a memberwise initializer to satisfy the init ......
Read more >
Protocol with associated type as property - Stack Overflow
2 Answers 2 · I think your answer needs some improvements. Notice that I want to have Item in Owner and Item in...
Read more >
Documentation - Object Types - TypeScript
Optional Properties. Much of the time, we'll find ourselves dealing with objects that might have a property set. In those cases, we can...
Read more >
4. Object Types - iOS 8 Programming Fundamentals with Swift ...
But I have not yet described how object types in general really work. ... Now let's talk about how to extract the associated...
Read more >
Getting started with associated types in Swift Protocols
Associated Types in Swift allow you to reuse code. ... protocol Collection { associatedtype Item var count: Int { get } subscript(index: ...
Read more >

github_iconTop Related Medium Post

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