Skip to content
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

Generic meta types #3779

Closed
d180cf opened this issue Jul 8, 2015 · 9 comments
Closed

Generic meta types #3779

d180cf opened this issue Jul 8, 2015 · 9 comments
Labels
Duplicate An existing issue was already created Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@d180cf
Copy link

d180cf commented Jul 8, 2015

As far as I know, in Flow there are so called "generic meta types" that can operate on other types:

type C = $Merge<{a: number}, {b: string}>; // C = { a: number, b: string }
type A = $Args<(a: number, b: string) => void>; // A = [number, string]

Such "type algebra" would be useful to construct function signatures and interfaces that are hard/impossible to construct with other techniques:

interface TaggedFunction<Callable extends (...args) => any> {
  type Args = $Args<Callable>;
  type RetV = $RetV<Callable>;

  (...args: ...Args): RetV;
  tag: number;
  bind<...T>(...args: ...T): TaggedFunction<(...args: $Concat<Args, ...T>) => RetV>;
}

Do you think this would be a useful addition to the type system?

@Lenne231
Copy link

Lenne231 commented Jul 8, 2015

I like the idea, but maybe this can also be solved with type providers (#3136). This would be way more flexible.

@danquirk
Copy link
Member

danquirk commented Jul 8, 2015

It seems like $Merge would be better described through intersection types:

// & not checked in yet but you can use | here to see how it works with unions
type c = typeof a & typeof b; 

$Args and $RetV look like they're essentially compile time reflection APIs.

@danquirk danquirk added the Suggestion An idea for TypeScript label Jul 8, 2015
@d180cf
Copy link
Author

d180cf commented Jul 9, 2015

Some of these meta types can have corresponding meta operators: & can denote $Merge, + can denote $Concat and so on; while other meta types, like $Args, won't have a corresponding operator. Such operators will essentially allow to write expressions that operate on types and construct other types.

@Lenne231, I'm not familiar with type providers, but a brief look at #3136 made me think that it's an imperative/procedural way of constructing types at compile time, while what I'm suggesting is a declarative way. If this is the case, then type providers is indeed a much more powerful feature.

@d180cf
Copy link
Author

d180cf commented Jul 23, 2015

Btw, does TS have plans to support nested types: interface Foo { type Bar = number; }? If yes, then it seems natural to have built-in nested types:

interface DecoratedFunction<F extends (...args) => any> {
  (...args): F.ReturnValueType;
  tag: number;
}

@danquirk
Copy link
Member

@d180cf local/nested types are already in, planned for 1.6: #3266

@Lenne231
Copy link

A "generic meta type" that creates a subset would also be nice, especially for functions that update data.

type A = $Sub<{ a: number; b: string }>; // A = { a?: number; b?: string }

function setState<T>(update : $Sub<T>) { ... }

setState<{ a: number; b: string }>({ a : 20 });

@danquirk danquirk added the Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. label Jul 27, 2015
@d180cf
Copy link
Author

d180cf commented Jul 28, 2015

It seems, that the appropriate place for such "generic meta types" (that would better be called "type expressions" or "computed types") is the .d.ts files. Currently they can contain only static type definitions, but could also contain "dynamic definitions":

/// [mytypes.d.ts]
declare module mytypes {
  export type BasicType = (a, b) => number;

  export type Intersection(a: ObjectLiteral, b: ObjectLiteral) {
    const r = new ObjectLiteral;
    for (const name of a.members) {
      if (name in b.members) {
        if (!Type.same(a.members[name], b.members[name]))
          throw CompileError(...);
        r.members[name] = a.members[name];
      }
    }
    return r;
  };
}

/// [sample.ts]
type X = { a: number; b: string };
type Y = { b: string; c: symbol };
type Z = mytypes.Intersection(X, Y);

Such computed types could be compiled in some special "compilation context" in which all these Type and ObjectLiteral are defined. Then we could go even further and allow "type operators":

/// [mytypes.d.ts]
declare module mytypes {
  export type "&" (a: ObjectLiteral, b: ObjectLiteral) {
    return Intersection(a, b);
  }
}

Of course, some of these computed types will be pretty common and will naturally become a part of the standard types library:

/// [lib.d.ts]
type "&" (a: ObjectLiteral, b: ObjectLiteral) { ... }

This should make it possible to express all fancy constructs that can exist in JS.

@benliddicott
Copy link

It seems that part of the motivating case could be met by extending typeof to arbitrary expressions, as per #4233.

type C = $Merge<{a: number}, {b: string}>; // C = { a: number, b: string }

Would then become

// $Merge woiuld provide 20 or so overloads with 1 to 20 parameters.
// Here's the two parameter overload.
function $Merge<T1>(a1: T1): (T1&T2);
function $Merge<T1, T2>(a1: T1, a2: T2): (T1&T2);
function $Merge<T1, T2, T3>(a1: T1, a2: T2, a3: T3): (T1&T2&T3);
function $Merge(...args){return null;}
type C = typeof $Merge({a: number}, {b: string});

Args is harder to see.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 22, 2016

this is already covered by #2710

@mhegazy mhegazy closed this as completed Feb 22, 2016
@mhegazy mhegazy added the Duplicate An existing issue was already created label Feb 22, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants