Standardize Terminologies #12

Open
unional opened this Issue Mar 4, 2016 · 38 comments

Projects

None yet

3 participants

@unional
Member
unional commented Mar 4, 2016

How to write typings

When you write typed definitions for DefinitelyTyped, you create a pull request on DefinitelyTyped with the corresponding .d.ts file and you are done. In the .d.ts file you write either an ambient internal module or ambient external module as in the handbook.

Things are a little bit different when you write a definition with Typings.

While it is definitely not harder than writing typed definitions for DefinitelyTyped, there isn't a clear term of reference on how to write a definition with Typings.

First things first...terminology

Going through the handbook and spec to understand everything you need to write typings is a great thing to do, but it isn't fun. Also, since TypeScript is rapidly improving, some information in the handbook is out of date.

Here are a list of terms that are relevant in writing typings so you can cut the chase.

If you like to learn by example, you can skim through this section and read the next one. Things will become more clear as you move along.

Typescript terminologies

ambient (declaration)

http://www.typescriptlang.org/Handbook#modules-working-with-other-javascript-libraries

We call declarations that don't define an implementation "ambient". Typically these are defined in .d.ts files. If you're familiar with C/C++, you can think of these as .h files or 'extern'.

  • Declaration that don't define an implementation
  • all .d.ts files
  • I think it is named so to describe "These files describe the target JS in ambient to the TS world"

ambient modules

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md

  • modules === external modules
    • i.e. ambient modules === ambient external module

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#ambient-modules

We could define each module in its own .d.ts file with top-level export declarations, but it's more convenient to write them as one larger .d.ts file. To do so, we use a construct similar to ambient namespaces, but we use the module keyword and the quoted name of the module which will be available to a later import.

  • Refers to both top-level export declaration and declare module "name" {.

ambient namespaces

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Namespaces.md#introduction

  • namespaces === internal modules
    • i.e. ambient namespaces === ambient internal module

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Namespaces.md#ambient-namespaces

  • declare namespace D3 + declare var d3: D3.Base to declare global object.
    • declare var d3 is needed because in the example D3 is a non-instantiated namespace.

external module

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md

  • external modules are now modules

export = and import = require()

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#export--and-import--require

  • When importing a module using export =, TypeScript-specific import X = require("module") must be used to import the module.

https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#support-for-default-import-interop-with-systemjs

  • In TypeScript 1.8, you can import X from 'module'; or import * as X from 'module';. The exact behavior depends on module: system|commonjs and allowSyntheticDefaultImports: true|false.

internal module

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Namespaces.md#introduction

  • internal modules are now namespaces

module

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#111-modules

  • ES2015 module
  • module === external module
  • Contain top-level export and import directives

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#16-classes

  • Not module pattern. module pattern === namespace === internal module

module keyword

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Namespaces%20and%20Modules.md

  • module X { is equivalent to the now-preferred namespace X {
    • When you write declare module X {, you are actually writing declare namespace X {.
    • i.e. you are writing namespace === internal module

Microsoft/TypeScript#6808

  • The module keyword will be gradually deprecated.

module pattern

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#110-namespaces

  • JavaScript module pattern: encapsulate private fields and methods using closure variables

namespace

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Namespaces.md#namespacing

Instead of putting lots of different names into the global namespace, let's wrap up our objects into a namespace.

  • Top-level namespace will be global (if the file is not a top-level declaration, see below)

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#10-namespaces

  • Formalization of the IIFE pattern

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#110-namespaces

  • Namespace is module pattern

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#101-namespace-declarations

Namespaces are either instantiated or non-instantiated. A non-instantiated namespace is a namespace containing only interface types, type aliases, and other non-instantiated namespace. An instantiated namespace is a namespace that doesn't meet this definition. In intuitive terms, an instantiated namespace is one for which a namespace instance is created, whereas a non-instantiated namespace is one for which no code is generated.

  • No code is generated for non-instantiated namespace
    • i.e. it can only be used as type
  • A namespace instance is created for instantiated namespace
    • i.e. at top-level, it creates a global namespace object

top-level declaration

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#23-declarations (need to scroll down a bit)

  • Top-level declarations in a source file with no top-level import or export declarations belong to the global namespace
    • This applies to both module and namespace
    • i.e. declare namespace X { creates a global namespace X.
  • Top-level declarations in a source file with one or more top-level import or export declarations belong to the module represented by that source file.
    • i.e. declare namespace X { in such file does not create global namespace X.

References

@unional
Member
unional commented Mar 4, 2016

It is a bit easier to discuss here. ๐ŸŒน

@unional
Member
unional commented Mar 5, 2016

Translating Typings terms to TypeScript terms

Ambient

Is probably just global as in global namespace

External module declaration

Based in TypeScript terms, what we described as external module declaration is likely ambient top-level module declaration. Since all typings are ambient, we might drop the word ambient and just call it top-level module declaration

Ambient module declaration

top-level namespace declaration

@blakeembrey
Member

Interesting on the translating. I thought I was pretty accurate to the TypeScript terms. Global is a new feature for augmentation. When you say all typings are ambient, are you talking about from the consumption perspective or the publishing perspective? When we publish, they definitely aren't ambient - the basic distinction from TypeScript is that ambient declarations have no top level import or export.

@unional
Member
unional commented Mar 6, 2016

When you say all typings are ambient, are you talking about from the consumption perspective or the publishing perspective?

They seems to define it neutrally:

We call declarations that don't define an implementation "ambient". Typically these are defined in .d.ts files. If you're familiar with C/C++, you can think of these as .h files or 'extern'.

@unional
Member
unional commented Mar 6, 2016

Global is a new feature for augmentation

The global I refer to is just global namespace, not global as in global augmentation.

@unional
Member
unional commented Mar 6, 2016

I'll continue to update the two above comments as we discuss. So that when we are done, they will be close to a complete doc. Feel free to edit them. ๐ŸŒน

@unional
Member
unional commented Mar 6, 2016

the basic distinction from TypeScript is that ambient declarations have no top level import or export.

On this note:
https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#ambient-modules

We could define each module in its own .d.ts file with top-level export declarations, but it's more convenient to write them as one larger .d.ts file. To do so, we use a construct similar to ambient namespaces, but we use the module keyword and the quoted name of the module which will be available to a later import.

  • Refers to both top-level export declaration and declare module "name" {.

Seems like they do not have a clean distinction between the two. That's why they have that paragraph there and it prohibits mapping.

However they have the the phrase top-level declaration, that's why I guess it could be ambient top-level module declaration or ambient top-level namespace declaration for global namespace.

@blakeembrey
Member

Sounds good, I think you've got this covered better than me at this point.

@unional
Member
unional commented Mar 6, 2016

๐Ÿบ
Some action items:

  • Complete original terms vs new terms table
  • Write up terminology doc
  • Write up how to write typings
  • Determine when (and how) to start using the new terms (and the release version)
  • Determine what are the impact on code
  • ...
@unional
Member
unional commented Mar 24, 2016

Terms to clarify:

  • ambient
  • env vs global
@unional
Member
unional commented Mar 24, 2016

source vs distribution channel vs package manager vs delivery mechanism

@unional
Member
unional commented Mar 24, 2016

lib vs env vs global in registry

@unional
Member
unional commented Mar 24, 2016

Script vs global in typings install. After a while I start thinking script make sense:
User is using the package in a script tag.

@unional unional referenced this issue in typings/typings Mar 24, 2016
Closed

Rename `ambient` usages to `global` #343

@johnnyreilly
Member

Conversation transferrred from Gitter:

https://github.com/typings/registry#structure

lib for shared environment functionality (ambient)
env for programming environment typings (ambient)
global for global libraries (ambient)

Hmm. Without examples those 3 definitions don't hold a great deal of meaning. Having read the above I couldn't tell you on what basis you'd choose where to put mocha / Angular / jquery etc. They all seem to be different shades of the same thing. And without a clear distinction, a satisfactory way to draw the line, I think the difference is unhelpful to users. As it stands I think this just provides confusion which could well be avoided. Happy to be put right if there is a clear rule that can be applied ๐Ÿ’

To summarise: we need clear definitions for the following:

  • lib
  • env
  • global

Without clear definitions I feel we should think about whether these terms are helpful and worth keeping.

@unional
Member
unional commented Apr 3, 2016

Related to the registry structure, I'm having difficulty in asking the right question in the generator:
https://github.com/typings/generator-typings/blob/beta/generators/app/index.js#L71-L86
Try to use lib, env global, but it doesn't seem to fit.

@blakeembrey
Member

@unional I'm guessing you've refactoring since then. What are you asking? I thought lib, env and global were pretty well defined (for inherently unstructured data):

  • lib - Use for "common utilities", basically stuff that doesn't fit into other ambient categories (E.g. the API definitions someone wanted to add recently)
  • env - Programming environments. E.g. window, atom, electron, node, etc. Stuff that comes with execution, even mocha ...
  • global - Global programming libraries. Still require an import somehow, but they are purely global.
@unional
Member
unional commented Apr 11, 2016

Wrap vs unwrap version terminology:
Microsoft/TypeScript-Handbook#242

@johnnyreilly
Member

To me at least lib and env are a little unclear.

window, atom, electron, node,

Totally.

mocha though I find tricky. Whilst it can be installed as a global for use on the command line, i think that's not the only use case? I'm on surer footing with karma and jasmine which are (I think) in the same bracket. I mostly use these as part of a gulp watch process. Though occasionally I will use the command line install (if I'm generating code coverage for instance) Is the rule for env that it's either part of an environment right from the off or that it can be made to be with an npm install -g?

That would seem to be a clear ish rule (and worth recording if so).

lib is still rather unclear to me tbh. What makes something not fit well into ambient?

Not trying to be difficult by the way. I'm just thinking that if it's not clear in our own minds (well, my own mind!) then that confusion is likely to result in things getting badly categorised in the Registry and users also rather puzzling over where they're supposed to find things.

@unional
Member
unional commented Apr 11, 2016

I've been bugging Blake to death on many things. I think he handles it well. ๐Ÿ˜œ

@johnnyreilly
Member

He does! ๐ŸŒท

@blakeembrey
Member

What makes something not fit well into ambient?

They are similar, I just wanted to separate the odd-balls that were external modules from the odd-balls that were ambient declarations. That's pretty much it.

Check out what's in lib/ right now, it's kind of random stuff: https://github.com/typings/registry/tree/master/lib.

@blakeembrey
Member

With mocha, jasmine, etc. you're right. There's both the env component and the npm component. That's something I've been trying hard to drill in everywhere, but I've had push back on thinking about it like this because it seems most people only want to think about it as a single module. However, if you used it as a single module that would introduce non-existing variables into the global scope.

@johnnyreilly
Member

Will check our lib and reflect. Ta.

there's both the env component and the npm component.

I'm not too sure what this means? Do you mean env is extended by the npm install -g use case?

However, if you used it as a single module that would introduce non-existing variables into the global scope.

I don't quite follow this. When I'm using jasmine I include the jasmine.d.ts which brings describe and it etc along to the party. But they are only part of my context in my test code. I have different TypeScript contexts for my src and for test. I'm guessing you're thinking about a use case where people share the same context for their test code and their src code?

@blakeembrey
Member

When I'm using jasmine I include the jasmine.d.ts which brings describe and it etc along to the party.

Yes, that's the env version. The other version would come along if you did import jasmine = require('jasmine'). Right now, most people are only interested in the env version anyway, but I believe we should try to keep them conceptually separate otherwise I'm introducing describe, it, etc. into production code.

@johnnyreilly
Member

otherwise I'm introducing describe, it, etc. into production code

Just for clarity - this is true in the case where you share context between your test and your src right? In that case you could write a describe in your src code and not have the compiler complain even though describe does not exist at execution time. Conversely, it's not possible where there are separate contexts for test and src.

Sorry to bang on, just want to be sure I understand you correctly.

@blakeembrey
Member

this is true in the case where you share context between your test and your src right?

Yes, correct.

Conversely, it's not possible where there are separate contexts for test and src.

It is possible with the current format (DefinitelyTyped) since it would mix the module and the environment definitions together in one file. That would cause usage where you're just using the module import syntax to also include the globals like describe, it, etc. It's a little edge-casey right now, but it's legitimate to me (I sometimes use the programmatic API without the env/globals that are part of mocha ..., like when writing a plugin for these systems).

@johnnyreilly
Member

It is possible with the current format (DefinitelyTyped) since it would mix the module and the environment definitions together in one file.

I don't quite follow that? As I understand it, contexts are built based on tsconfig.json and import statements.

Perhaps an example. Here's a repo of mine. It has this test tsconfig.json which includes jasmine.d.ts and react-addon-test-utils.d.ts. The same repo actually has 2 src contexts; one for the react demo and one for the npm package library which create contexts which do not include either jasmine.d.ts and react-addon-test-utils.d.ts.

In the test code here we do not use import to bring jasmine in; rather it's part of the environment brought in by karma.conf.js.

So in this case jasmine is already part of env. So to loop back again:

It is possible with the current format (DefinitelyTyped) since it would mix the module and the environment definitions together in one file.

I don't think it is possible to use describe, it in either of the src contexts without tsc going:

image

But it is possible? ๐Ÿ˜•

@johnnyreilly
Member

BTW, whilst jasmine becomes part of the environment, react-addons-testutils does not (imported). Sorry for confusion.

@blakeembrey
Member

I don't think we're discussing the same thing. Let's try to reset. You've got the env usage fine (which is just "put stuff in the global namespace for testing"). However, that only occurs when running in a test environment. Sometimes, these modules can be used programmatically via require. That does not populate the global environment.

Simple example: https://github.com/blakeembrey/co-mocha. That's a plugin manipulating the programmatic API of Mocha, not the environment mocha generates when executing tests. It's entirely probable when working with these types of plugins that you want one interface or the other - not both. Hence, I would like to promote, where possible, clear separation of concerns. This may be just a pipe dream of mine though.

@johnnyreilly
Member

You may be right about the ๐Ÿšฌโ˜ (closest emoji gets to "pipedream).

I think I follow you. Unfortunately I can't see any examples in the Registry that nicely demonstrate the delineation. I kind of feel that if we want this to happen we need something to point at and say "do it like this! Behold the wonderful good practice!"

Any candidates? Mocha looks like it only appears in env? Should it have counterparties in global? Should it be different if so? And if so, in what way?

@blakeembrey
Member

Sure, I can go in and do one as an example. Mocha is what I'm most familiar with - it would be putting one version in env and another in npm. On a side-note, preferably we would publish with the package with two definitions. E.g. npm install mocha, then require('mocha') would point to the typings in package.json (normal behaviour) which gives up the programmatic API, then using the env interfaces would require some manual hookup (E.g. put node_modules/mocha/env.d.ts into tsconfig.json or typings install npm:mocha/env.d.ts -SA).

@johnnyreilly
Member

Thanks - that'd be v helpful!

Btw is there a scenario when a Typing could appear in env as well as lib as well as global? Or is it one only?

@blakeembrey
Member

Btw is there a scenario when a Typing could appear in env as well as lib as well as global? Or is it one only?

Yes, env + global (because global is the same spectrum as npm or bower).
No, env + lib or global + lib (because lib are random things that don't really fit elsewhere).

Edit: Not to say that lib isn't useful, it's just they aren't a library or a specific definition - but really just helpers people are sharing.

@johnnyreilly
Member

Ta. So if something is in lib it isn't anywhere else?

@blakeembrey
Member

Nope, definitely not.

@johnnyreilly
Member

Cool. Rules as understood so far:

env - it's either part of an environment right from the off (eg node) or that it can be made to be with an npm install -g (eg mocha)

global - brings in new items to the global scope. (eg knockout)

lib - the awkward package at the back of the class that just refuses to fit in

npm - packages on npm

@blakeembrey
Member

๐Ÿ‘ The only thing I'd change is phrasing on mocha. It's not the global installation that makes it provide an environment. I'll think about how to phrase it, but it's more that it provides environment variables based on specific execution. E.g. node via node CLI, mocha via mocha CLI, browsers via browsing, etc.

@johnnyreilly
Member

Yeah - you're right. Need careful description. ๐Ÿ‘

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment