-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposal] External Module Type #13231
Comments
One thing about this proposal is that it only enforces a contract between a module and a type - in other words, it only guarantees the values that exist on the module. Something I would kind of like to see is the idea of a contract on the shape of the module (or namespace) as a whole - a guarantee that a module contains certain values, types, and namespaces. There are definitely other languages that do this, so it's not unheard of. That said, we don't necessarily have to go down that route. |
Indeed, a module interface could shape the entire module (with types and nested namespaces). But I think a module should also implements a basic type/interface. Maybe a |
|
dup i strongly oppose this in favor of unifying modules (namespaces) with objects per #8358 |
This also relates to #11611 |
@Aleksey-Bykov Even if you unify namespaces with objects, you need additional syntax to ascribe types to external modules (for which the "implementation" is not neatly enclosed, but is instead supplied by scattered export statements). |
@masaeedu I believe such types already exist. Consider // module-a.ts
export default function () {}
export const a = 1;
export let b = 'hello';
// module-b.ts
import * as moduleA from './module-a';
export const a: typeof moduleA = {
a: moduleA.a,
b: moduleA.b,
default: moduleA.default
}; |
I'm not sure I understand your example. This is not asserting that your
module satisfies an interface, but rather that an arbitrarily constructed
object consisting of the module's members is assignable to the module's
type.
You still can't ascribe a type to the module; the type will be driven by
what you export, and there's no way to dictate right or wrong exports. The
goal is to receive a type error where I do `export const x = 2` in a module
that I claim implements `{ x: string }`.
…On Sep 19, 2017 8:25 AM, "Aluan Haddad" ***@***.***> wrote:
@masaeedu <https://github.com/masaeedu> I believe such types already
exist. Consider
// module-a.tsexport default function () {}export const a = 1;export let b = 'hello';
// module-b.tsimport * as moduleA from './module-a';
export const a: typeof moduleA = {
a: moduleA.a,
b: moduleA.b,
default: moduleA.default
};
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#13231 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADgPyHKOSgbA-lGlRHpoc73gXGE-Oijvks5sj7KbgaJpZM4LYUYI>
.
|
@masaeedu, not sure i am following, consider an example below:
|
I have `interface Foo { x: string }`. How do I ensure the sum total of
everything I am exporting in myfancymodule is compatible with `Foo`, and
get type errors on my export statements when this is not the case?
…On Sep 19, 2017 9:52 AM, "Aleksey Bykov" ***@***.***> wrote:
@masaeedu <https://github.com/masaeedu>, not sure i am following,
consider an example below:
const type Ns<T> = {
type List: List<T>;
value: number;
}
const ns: Ns<T> = {
value: 1;
};
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#13231 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADgPyCrJg_cX0POkpd-qmzI3iPmrar58ks5sj8cPgaJpZM4LYUYI>
.
|
I do not want to deconstruct |
well, as far as the syntax it could have looked like this
or better yet (if we unify objects and namespaces)
or simply and more idiomatic
(although it would be a sub-module) as to the original topic it indeed requires new special syntax/keywords within a module to indicate it complies to an interface:
|
@Aleksey-Bykov it depends. Although namespaces and objects are unfortunately not unified, you can still, by convention establish a type for an export in a single place by creating a declaration and exporting it. @masaeedu I see what you are getting at now. You want to be able to declare the interface mandated by a module and then receive an error if the contract is broken. |
@aluanhaddad although a type can be exported it cannot be closed over other types and it's a huge maintainability pain, consider interface T<A extends B, B extends C, C extends D, D extends E, E extends F, F> {
type X = (value: A | B | C) => D;
type Y = (value: B | C | D) => E;
type Z = (value: C | D | E) => F;
} namespace T {
export type X<A extends B, B extends C, C extends D, D> = (value: A | B | C) => D;
export type Y<B extends C, C extends D, D extends E, E> = (value: B | C | D) => E;
export type Z<C extends D, D extends E, E extends F, F> = (value: C | D | E) => F;
} |
@Aleksey-Bykov that would be very valuable, I think there is an issue open for it actually, #17588, and I was going to write that if objects and namespaces were unified as you propose, that the above behavior would be a pleasant, natural consequence, but I see you have already stated just that there 😁 |
With code splitting working with const dosometstuff = async (moduleToBeImported: typeof module) => {
let imported = await import(moduleToBeImported);
// ...
}
// Usage...
await dosometstuff("./SomeModule"); Naturally above does not work yet, but it would be nice to typecheck that "./SomeModule" indeed is a module. Perhaps with some constraints on it too, for example that it exports at least And btw, if the module weren't some magic the
|
It seems this is already mostly satisfiable with the |
@Jessidhia You're right. I close the issue |
Introduction
Currently, TypeScript allows to ensure typings on differents levels using
type
,interface
orclass
.There are numbers of scenarios where we want to ensure typings on the
module
level.Scenario 1: Module Interface
Many libraries can be extended using plugins which are loaded as modules.
These libraries' maintainers could define an
interface
which should be implemented by the module.Scenario 2: Module proxy
Imagine a library which abstract RPC services. On the server part, you define services as modules and on the client part, you get Promised proxies of these services which you can use to remote call your service methods.
Scenario 3: Inline module typing
By extending the preceding scenario, we could imagine that the library also provides a module loader plugin for its managed services.
Scenario 4: Wildcart module typing
This time, we have a library that proxy services in a
Web Worker
.Language Features
Syntatic
What is the grammar of this feature?
export implements IPlugin
(could be writtenimplements IPlugin
)typeof module("module/path")
import myModule from "myModule" as Type
typeof module("*")
in wildcart module definitionAre there any implications for JavaScript back-compat? If so, are they sufficiently mitigated?
Does this syntax interfere with ES6 or plausible ES7 changes?
Semantic
What is an error under the proposed feature? Show many examples of both errors and non-errors
How does the feature impact subtype, supertype, identity, and assignability relationships?
How does the feature interact with generics?
type
(like an Interface is), it should interact with generics.Emit
What are the effects of this feature on JavaScript emit? Be specific; show examples
Does this emit correctly in the presence of variables of type ‘any’? Features cannot rely on runtime type information
What are the impacts to declaration file (.d.ts) emit?
export implements...
informationsDoes this feature play well with external modules?
Compatibility
Is this a breaking change from the 1.0 compiler? Changes of this nature require strong justification
Is this a breaking change from JavaScript behavior? TypeScript does not alter JavaScript expression semantics, so the answer here must be “no”
Is this an incompatible implementation of a future JavaScript (i.e. ES6/ES7/later) feature?
Other
Can the feature be implemented without negatively affecting compiler performance?
What impact does it have on tooling scenarios, such as member completion and signature help in editors?
TODO
The text was updated successfully, but these errors were encountered: