Ember-cli-typescript: [RFC / Quest] Decomposing types into @ember modules

Created on 26 Aug 2018  路  11Comments  路  Source: typed-ember/ember-cli-typescript

Motivation

The 2.16 changes around how framework modules are consumed was intended to get people importing parts of the framework in this new way, with the aim of making it possible to incrementally refactor ember-source into independent npm modules without breaking consumers' apps.

Goals

  • [x] Allow consumers to use the Ember types by importing from the appropriate @ember/* modules
  • [x] Break the types up into individual files instead of one massive index.d.ts

    • [x] Allow our types to be more easily browsable for consumers, by reflecting the paths of the ES6 imports (i.e., import ComputedProperty from '@ember/object/computed'; should be found in node_modules/@types/@ember/object/computed.d.ts

  • [x] Make the @ember modules the source of truth, with the 'ember' module re-exporting in the pre-2.16 style
  • [x] These changes should be incremental and non-breaking, assuming consumers stay reasonably up-to-date with ember-cli-typescript
  • [x] Consumers should get clear and actionable feedback if any action is required on their part to receive a great developer experience

Nice To Have

  • [x] Replace most of our declare module '@ember/foo' stuff with simply having a *.d.ts file in the right place.
  • [x] Extremely low churn in consumers' package.json

Proposed Strategy

  • [x] 1. Re-export everything from 'ember' through the appropriate @ember/* modules

    This is already done.

  • [x] 2. Create a new @types/ package for each of the top-level @ember modules that ember-source ships.

    Most of you are probably aware of the types-publisher limitations around packages where npm module and ES6 module paths misalign. This is one reason we have everything in a single massive index.d.ts file.

    Additionally, there are limitations around scoped packages in types-publisher prevent us from exposing multiple @ember/* types from a single module (other than a bunch of declare module '@ember/******' stuff. For this reason, we cannot have a single (conceptual equivalent of) @types/@ember that contains everything. We must create individual subfolders for @types/ember__object, @types/ember__component, etc... Each of these will be independently versioned and independently published by types-publisher.

    • [x] 2.1 Create a new *.d.ts file for every ES6 module we currently provide types for

      These modules will initially contain only the re-export stuff (one *.d.ts file per ES6 module we currently provide types for), bringing in @types/ember as a dependency via ~a triple-slash directive~ a module import. The only tests that should be in these new type packages are those that protect against regression within the re-exporting.

  • [x] 3. Add the new @types/ember__* packages as dependencies to @types/ember

  • [x] 4. In no less than one PR per @ember package, incrementally move the source of truth for the types from @types/ember to the respective @types/ember__*

    Once each of these PRs is complete, @types/ember will then depend on the respective @types/ember__* via a triple-slash directive.


PROJECT DASHBOARD

RFC

All 11 comments

For 3., is it not desirable to just make @types/ember__* dependencies of @types/ember rather than adding them individually?

For 3., is it not desirable to just make @types/ember__* dependencies of @types/ember rather than adding them individually?

You're absolutely right. I must have been drinking when I wrote the above :P

I think my only hesitation was wanting to better understand that bit; in its revised form, I'm 馃憤 on this plan.

Going by the mappings in rfc176-data, this should result in 23 new @types/ember__* packages

@ember/application
@ember/array
@ember/canary-features
@ember/component
@ember/controller
@ember/debug
@ember/engine
@ember/enumerable
@ember/error
@ember/instrumentation
@ember/map
@ember/object
@ember/polyfills
@ember/routing
@ember/runloop
@ember/service
@ember/string
@ember/template
@ember/template-compilation
@ember/template-factory
@ember/test
@ember/utils
@ember/version

@dwickern I think that some of those do not ~have a public API~ have type information in our current @ember/types
example: @ember/canary-features

Here's the minimum list I have so far

@ember/application
@ember/array
@ember/component
@ember/controller
@ember/debug
@ember/engine
@ember/enumerable
@ember/error
@ember/instrumentation
@ember/map
@ember/object
@ember/polyfills
@ember/routing
@ember/runloop
@ember/service
@ember/string
@ember/test
@ember/utils

How should we handle the contributors for these individual @types/ember__ packages?

I'd love to see us end up with domain-specific maintainers (i.e., a few people watch over @types/ember__components, others watch @types/ember__runloop, etc...

Should we consider this a new package with a new contributors list, or copy everyone from @types/ember for the initial commit?

What are you using to determine which of those modules are public? I thought their presence in rfc-176 implies that they're all public. For example, @ember/canary-features corresponds to Ember.FEATURES.

@dwickern At least for now, I'm focused on existing modules that we have types for (i.e., our @types/ember index.d.ts has a declare module "@ember/foo"). I'll walk back my potentially incorrect statement about public vs. private.

example: @ember/template-factory -- we don't provide types for this now so we don't need to act on it now. If there's some genuinely public API from this package in the future, we can treat it accordingly.

This quest now has its own project dashboard here
https://github.com/orgs/typed-ember/projects/2

Excellent work here, @mike-north! Thanks for driving this forward!

Was this page helpful?
0 / 5 - 0 ratings