GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Mapped types by ahejlsberg · Pull Request #12114 · microsoft/TypeScript

Conversation

@ahejlsberg

@ahejlsberg Anders Hejlsberg (ahejlsberg) commented Nov 9, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

This PR introduces Mapped Types, a new kind of object type that maps a type representing property names over a property declaration template. In combination with index types and indexed access types (#11929), mapped types enable a number of interesting and useful type transformations. In particular, mapped types enable more accurate typing of intrinsic functions such as Object.assign and Object.freeze as well as APIs that map or transform shapes of objects.

A mapped type takes one of the forms

{ [ P in K ] : T }
{ [ P in K ] ? : T }
{ readonly [ P in K ] : T }
{ readonly [ P in K ] ? : T }

where P is an identifier, K is a type that must be assignable to string, and T is some type that can use P as a type parameter. A mapped type resolves to an object type with a set of properties constructed by introducing a type parameter P and iterating it over the constituent types in K, for each such P declaring a property or index signature with the type given by T (which possibly references P as a type parameter). When P is a string literal type, a property with that name is introduced. Otherwise, when P is type string, an index signature is introduced.

type Item = { a: string, b: number, c: boolean };

type T1 = { [P in "x" | "y"]: number };  // { x: number, y: number }
type T2 = { [P in "x" | "y"]: P };  // { x: "x", y: "y" }
type T3 = { [P in "a" | "b"]: Item[P] };  // { a: string, b: number }
type T4 = { [P in keyof Item]: Date };  // { a: Date, b: Date, c: Date }
type T5 = { [P in keyof Item]: Item[P] };  // { a: string, b: number, c: boolean }
type T6 = { readonly [P in keyof Item]: Item[P] };  // { readonly a: string, readonly b: number, readonly c: boolean }
type T7 = { [P in keyof Item]: Array<Item[P]> };  // { a: string[], b: number[], c: boolean[] }

Type relationships involving mapped types are described in #12351. For information on type inference involving mapped types, see #12528 and #12589. For information on preservation of property modifiers with mapped types, see #12563.

The following four mapped types are predefined in lib.d.ts as of #12276:

// Make all properties in T optional
type Partial<T> = {
    [P in keyof T]?: T[P];
};

// Make all properties in T readonly
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

// From T pick a set of properties K
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
}

// Construct a type with a set of properties K of type T
type Record<K extends string, T> = {
    [P in K]: T;
}

Some functions that use the above types:

function assign<T>(obj: T, props: Partial<T>): void;
function freeze<T>(obj: T): Readonly<T>;
function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>;
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>;

And some code that uses the functions:

interface Shape {
    name: string;
    width: number;
    height: number;
    visible: boolean;
}

function f1(s1: Shape, s2: Shape) {
    assign(s1, { name: "circle" });
    assign(s2, { width: 10, height: 20 });
}

function f2(shape: Shape) {
    const frozen = freeze(shape);
    frozen.name = "circle";  // Error, name is read-only
}

function f3(shape: Shape) {
    const x = pick(shape, "name", "visible");  // { name: string, visible: boolean }
}

function f4() {
    const rec = { foo: "hello", bar: "world", baz: "bye" };
    const lengths = mapObject(rec, s => s.length);  // { foo: number, bar: number, baz: number }
}

The mapObject example above shows how type inference can be used for mapped types. When inferring from an object type S to a mapped type { [P in K]: T }, keyof S is inferred for K and S[keyof S] is inferred for T. In other words, a literal union type of all property names in S is inferred for K and a union of all property types in S is inferred for T.

Another common pattern:

// A proxy for a given type
type Proxy<T> = {
    get(): T;
    set(value: T): void;
}

// Proxify all properties in T
type Proxify<T> = {
    [P in keyof T]: Proxy<T[P]>;
}

function proxify<T>(obj: T): Proxify<T> {
    // Wrap proxies around properties of obj
}

function f5(shape: Shape) {
    const p = proxify(shape);
    let name = p.name.get();
    p.visible.set(false);
}

Related issues include #1295, #2710, #4889, #6613, #10725, #11100, #11233.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

tinganho, Igorbek, yortus, normalser, jwbay, svieira, jkillian, alitaheri, s-panferov, HerringtonDarkholme, and 143 more reacted with thumbs up emoji unlanin reacted with thumbs down emoji jwbay, svieira, jkillian, alitaheri, ronzeidman, HerringtonDarkholme, aluanhaddad, seansfkelley, kitsonk, tiagoefmoraes, and 61 more reacted with hooray emoji Igorbek, jwbay, gabomgp, alitaheri, HerringtonDarkholme, aluanhaddad, sanex3339, arusakov, EmielM, wclr, and 52 more reacted with heart emoji
All reactions
  • 👍 153 reactions
  • 👎 1 reaction
  • 🎉 71 reactions
  • ❤️ 62 reactions
Anders Hejlsberg (ahejlsberg) added 16 commits November 3, 2016 06:09
@ahejlsberg
Parsing of mapped types
7cd39e3
@ahejlsberg
Parse '[P in K]' part of mapped type as a type parameter declaration
d1a8af5
@ahejlsberg
Introduce MappedType in type checker
fc450a2
@ahejlsberg
Merge branch 'master' into mappedTypes
ecdb74c
@ahejlsberg
Attach symbols to mapped types
7807ac9
@ahejlsberg
Introduce instantiateCached function
1c7b397
@ahejlsberg
Handle readonly and optional properties + index signatures
507ab30
@ahejlsberg
Handle recursion in mapped type display
2564e1c
@ahejlsberg
Validate constraint type in mapped type
5de63a7
@ahejlsberg
Correct symbol display for type parameter of mapped type
de93876
@ahejlsberg
Improve sharing by re-instantiating top level type aliases
9f3aa38
@ahejlsberg
Type inference for mapped types
8aef1e6
@ahejlsberg
Merge branch 'master' into mappedTypes
7ca5923
# Conflicts:
#	src/compiler/checker.ts
@ahejlsberg
Make keyof T assignable to and subtype of string | number
a562d6e
@ahejlsberg
Add relations for keyof S / keyof T and [P in S]: X / [P in T]: X
cf2953b
@ahejlsberg
Don't include private/protected properties in keyof T
aca7e2f
@msftclas Microsoft Contribution License Agreements (msftclas) added the cla-not-required label Nov 9, 2016
@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) mentioned this pull request Nov 9, 2016
Partial Types #11233
Closed
@jkillian

Jason Killian (jkillian) commented Nov 9, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

This is very cool! It'll be great to be able to have stronger typings for all the sorts of utility-type function this will support.

Just curious, would this allow for typings for a function like _.omit? As far as I can tell, this would require an additional, orthogonal, type operator?

function omit<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, (keyof T) - K>;
guillaume86, alinhle, marcomorain, andrew-w-ross, leonadler, mkusher, ikokostya, vincekovacs, daisylb, and canufeel reacted with thumbs up emoji
All reactions
  • 👍 10 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexGalays

Alexandre Galays (AlexGalays) commented Nov 9, 2016

Copy link
Copy Markdown

Can it handle non shallow transformations ?

Like

function deepAssign<T>(obj: T, props: DeepPartial<T>): void;

bradenhs reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@alitaheri

Ali Taheri Moghaddar (alitaheri) commented Nov 9, 2016

Copy link
Copy Markdown

Jason Killian (@jkillian) Probably after object-rest is in.

Alexandre Galays (@AlexGalays) Nope, I checked out the branch. I didn't find a way this can be done.

I tried 2 level partial, this is the best I could get:

type DeepPartial<T> = {
  [P in keyof T]?: T[P] | {[S in keyof T[P]]?: T[P][S]};
};

type A = { a: number, b: { c: boolean; d: string; } }

type B = DeepPartial<A>; 

const b: B = { b: {c: {}} };

the second part: {[S in keyof T[P]]?: T[P][S]} always ends up being {} and since interfaces cannot have this signature there is no way to recursively define it:

interface DeepPartial<T> {
  [P in keyof T]?: T[P] | DeepPartial<T[P]>; // nope :(
}

Also, There is no way to distinguish between objects and non-objects so everything will have | {} appended to it.

This PR is really really great so far, I love it ❤️ ❤️

I don't think deep partial is possible at the moment. unless it is defined as a builtin modifier (deepPartial) or magic interface DeepPartial<T>

GoToLoop and bradenhs reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@niieani Bazyli Brzóska (niieani) mentioned this pull request Nov 9, 2016
Implement subtraction and rest type once TS 2.1 lands types/rethinkdb#2
Open
@HerringtonDarkholme

Herrington Darkholme (HerringtonDarkholme) commented Nov 9, 2016

Copy link
Copy Markdown
Contributor

This might be irrelevant but I really cannot hold the urge to say here:

the most exciting moment when using TypeScript is that after a magic pull request, all the sudden I can express a lot of semantics I couldn't before. That's the very freedom in programming world.

This feature is so awesome. Thanks Anders Hejlsberg (@ahejlsberg) and TypeScript team. Make FrontEnd Great Again!

alitaheri, aluanhaddad, sandord, jonaskello, marcomorain, rd-dev-ukraine, nicotoumetis, IanYates, rictic, wwwillchen, and 5 more reacted with thumbs up emoji normalser, Lenne231, guncha, jwbay, jkillian, svieira, niieani, forabi, alitaheri, mariusschulz, and 9 more reacted with laugh emoji masak and debajyoti-thetaonelab reacted with heart emoji
All reactions
  • 👍 15 reactions
  • 😄 19 reactions
  • ❤️ 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Nov 9, 2016

Copy link
Copy Markdown
Member Author

Jason Killian (@jkillian) No active plans to support a type subtraction operator. It's unclear how such an operator would function across all types. That said, it might be possible to have a limited form that only works on primitive (and thus literal) types and unions thereof. That would suffice for the scenarios where you're subtracting keys from a keyof T.

Alexandre Galays (@AlexGalays) Ali Taheri Moghaddar (@alitaheri) We currently restrict recursive use of a mapped type, but it's possible to lift that restriction. However, in actual use we'd still need some form of recursion limiter to avoid spiraling down an infinite series of nested mapped type applications. Ideally some sort of type parameter constraint or modifier you could use on a type alias for a mapped type to indicate that applications should short-circuit for certain types. That way you could for example declare DeepPartial<T> to simply yield T when T is a primitive type.

Herrington Darkholme (@HerringtonDarkholme) Thanks! Really appreciate your excitement for our work.

forabi, alitaheri, guncha, jkillian, HerringtonDarkholme, svieira, wclr, fredgalvao, aluanhaddad, davidk-zenefits, and 5 more reacted with thumbs up emoji alitaheri, jkillian, tinganho, HerringtonDarkholme, svieira, wclr, fredgalvao, aluanhaddad, GoToLoop, CunningFatalist, and 5 more reacted with heart emoji
All reactions
  • 👍 15 reactions
  • ❤️ 15 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg
Properly implement type relationship for '[P in S]: X' and '[P in T]: Y'
3dd11e4
@kourge

Wil Lee (kourge) commented Nov 9, 2016

Copy link
Copy Markdown

This is highly exciting! And here I thought strict null check was the best thing since sliced bread, and then this came along.

I think "mapped types" is a somewhat vague term, but seeing the syntactic form of this reminds me of dictionary comprehensions in Python, so perhaps "type comprehension" could be a more descriptive term?

evincarofautumn and dheerajbhaskar reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhegazy

Mohamed Hegazy (mhegazy) commented Nov 10, 2016

Copy link
Copy Markdown
Contributor

🚲 🏠 comment. Why not use for as in

type Partial<T> {
  [for P in keyof T]?: T[P]
}

this makes the iterative nature of the construct more prominent, and would allow for a future branch option using if a la Python generator expressions.

niieani, svieira, aluanhaddad, pimterry, tomasdeml, dawidcxx, GoToLoop, and knee-cola reacted with thumbs up emoji
All reactions
  • 👍 8 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@HerringtonDarkholme

Herrington Darkholme (HerringtonDarkholme) commented Nov 10, 2016

Copy link
Copy Markdown
Contributor

Mohamed Hegazy (@mhegazy) did you mean something like

type SubstractType<T, K> {
  [for P in keyof T if !(P in keyof K)]: T[P]
} 
SubstractType<{name: string, age: number}, {age: number}> // {name: string}

Type predicate for filtering property?

GoToLoop and niieani reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Nov 10, 2016
Strictly typed component decorator support DefinitelyTyped/DefinitelyTyped#11101
Merged
react-redux's connect cannot be used as a decorator: type "is not assignable to type 'void'" DefinitelyTyped/DefinitelyTyped#9951
Closed
@zpdDG4gta8XKpMCd

ZpdDG4gta (zpdDG4gta8XKpMCd) commented Dec 9, 2016

Copy link
Copy Markdown

typescript chose to sacrifice correctness for the sake of "convenience" and ease of learning for attracting as much untutored audience as possible, basically leveling everyone down to the least common denominator

here is the list of hard choices in the making: https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3A%22by%20design%22

Elephant-Vessel reacted with confused emoji
All reactions
  • 😕 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexGalays

Alexandre Galays (AlexGalays) commented Dec 9, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Silvio (@silviogutierrez)

Well, in my case I don't want users of my function to extend the base structural type with more properties; I want the full extent of properties declared upfront for typesafety. That rules out returning T & U for me.

Also, be careful with & as it's a bit broken.

If you do

  type A = { oops: ['1', '2', '3'] }
  type B = { oops: 333 }
  type C = A & B

You would probably expect an Error, but instead it compiles just fine and the type of oops inside C is string[] & number which makes no sense.

Partial and the likes seem to have fewer applications that previously thought in their current forms :( It still doesn't solve the React setState problem too :

type State = { veryImportant: number }

// This compiles fine with all the mandatory flags (strictNullChecks, etc)
// if we use Partial<State>
// This is a huge invariant violation and can happen very easily for instance
// by setting `veryImportant` to a nullable variable.
this.setState({ veryImportant: undefined })

Let's start creating some focused bug tickets rather than complaining on this PR :p

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kayhorrors Kay (kayhorrors) mentioned this pull request Dec 11, 2016
Use keyof to improve type safety DefinitelyTyped/DefinitelyTyped#13254
Closed
6 tasks done
@yortus Troy Gerwien (yortus) mentioned this pull request Dec 13, 2016
Expressions for string-literal types #12861
Closed
@jkillian

Jason Killian (jkillian) commented Dec 13, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

I'm trying to write typings for React's update helper and am struggling a bit.

Here's what I have so far, trying to get things working for a subset of the library's functionality for now. I'm having a few issues which are noted in the code below:

type Command =
    { $set: any; } |
    { $merge: {} } |
    { $apply(value: any): any; };
type Update<T> = { [P in keyof T]?: Update<T[P]> | Command; };
declare function update<T>(value: T, updateObj: Update<T>);

type Foo = {
    a: number;
    b: { b1: number; };
}
let bar: Foo = { a: 1, b: { b1: 2} };

// doesn't work without explicit <Foo>:
// The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
//   Type argument candidate 'Foo' is not a valid type argument because it is not a supertype of candidate '{ a: { $set: number; }; }'.
//     Types of property 'a' are incompatible
//       Type '{ $set: number; }' is not assignable to type 'number'.
update<Foo>(bar, { a: { $set: 3 } })

// also doesn't work without <Foo>
update<Foo>(bar, { b: { b1: { $set: 4 } } })

// shouldn't work at all, but does
update<Foo>(bar, { b: 7 });

Any ideas for ways to improve things? At the least, I think it may be an improvement over the current typings, but I wish it could be even better. Having to explicitly specify the type of T when calling update is a big usability issue in my mind

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@PyroVortex

PyroVortex commented Dec 13, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

You can accomplish it thusly:

type Update<T, K extends keyof T> = { [P in K]: Command | NestedUpdate<T[P]> };
type NestedUpdate<T> = { [P in keyof T]?: Command | NestedUpdate<T[P]> };
declare function update<T, K extends keyof T>(value: T, updateObj: Update<T, K>);

The problem is that once you get more than one layer deep, it stops actually validating the type.

SlurpTheo reacted with thumbs up emoji jkillian reacted with hooray emoji
All reactions
  • 👍 1 reaction
  • 🎉 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jkillian

Jason Killian (jkillian) commented Dec 13, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

PyroVortex Thanks! That works much better! I made an updated example demonstrating the now working cases and the failure case you mentioned in case anyone's interested

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexGalays

Alexandre Galays (AlexGalays) commented Dec 14, 2016

Copy link
Copy Markdown

PyroVortex Seems a bit strange

  • K extends keyof T; why use a second type parameter to have a subset of the keys if the keys are already all optional with ? anyway?
  • When Update is called recursively, It is not passed a subset of keys but the full set of keys which is not consistent with the first level

Anyway, as seen in #12769 (comment), you would have to use the nightly build to get close to what you want without some bad side effects currently in 2.1.4.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jkillian

Jason Killian (jkillian) commented Dec 14, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Ah, thanks for the reference to #12769 Alexandre Galays (@AlexGalays). It looks like Anders' code is quite similar to what I had tried in this comment. Perhaps upgrading to the nightly is the right solution for me here

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Vincent Prouillet (Keats) referenced this pull request in infernojs/inferno Dec 20, 2016
Luke Sheard
Refactor typings
c3e6366
@aindlq Artem (aindlq) mentioned this pull request Dec 28, 2016
#143 Make Kefir.combine() also accept sources as objects kefirjs/kefir#225
Merged
@zuzusik Viktor Zozuliak (zuzusik) mentioned this pull request Dec 30, 2016
[sinon] properly type sinon.createStubInstance DefinitelyTyped/DefinitelyTyped#13522
Merged
8 tasks done
@mkusher Aleh Kashnikau (mkusher) mentioned this pull request Jan 1, 2017
Mapped type for combineReducers in index.d.ts reduxjs/redux#2177
Closed
@patrick91 Patrick Arminio (patrick91) mentioned this pull request Feb 2, 2017
TypeScript: Add support of typed themes styled-components/styled-components#432
Merged
@asfernandes Adriano dos Santos Fernandes (asfernandes) mentioned this pull request Feb 5, 2017
Support readonly type operator to allow correct definition of Object.freeze #10725
Closed
@wclr

Alex (wclr) commented Apr 4, 2017

Copy link
Copy Markdown

Is it possible to get the following, get only those props from an object, that present in another object :

function takeProps<Obj>
  (props: {[K in keyof Obj]?: true}, obj: Obj) {
  const newObj: any = {}
  for (let key in props) {
      newObj[key] = obj[key]
  }
  return newObj as {[K in keyof typeof props]: number}
}

takeProps({a: true, c:  true }, {
  a: 1,
  b: 2,
  c: 3
}) // => here I wan't be available only `a` and `c`, but get `a`, `b`, and `c`
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@PyroVortex

PyroVortex commented Apr 4, 2017 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Renamed in favour of (@whitecolor)

function takeProps<T, K extends keyof T>(props: {[P in K]: true }, obj: T): {[P in K]: T[P]}

The above declaration has the behavior you are describing.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wclr

Alex (wclr) commented Apr 4, 2017

Copy link
Copy Markdown

PyroVortex thanks very much)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wclr

Alex (wclr) commented Apr 5, 2017

Copy link
Copy Markdown

There is another question: is it possible to type a function that gets object map with values that are actually functors and returns mapped object applying map method of each functor.

interface A {
  map: () => number  
}

interface B {
  map: () => string  
}


let a: A = {
  map: () => 1
}

let b: B = {
  map: () => 'str'
}


function getMapped(sources: {[index: string]: {map: () => any}}) {
  // implementation
  const mapped: {[key in keyof typeof sources]: any} = {}
  for (const key in sources) {
    mapped[key] = sources[key].map()
  }
  return mapped
}

getMapped({a, b}).a // => should be 1
getMapped({a, b}).b // => should be 'str'
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@spion

spion (spion) commented Apr 5, 2017

Copy link
Copy Markdown

Yes

interface A {
  map: () => number  
}

interface B {
  map: () => string  
}


let a: A = {
  map: () => 1
}

let b: B = {
  map: () => 'str'
}

type MapsTo<T> = { map: () => T }

type MapSources<T> = {[K in keyof T]: MapsTo<T[K]> }


function getMapped<T>(sources: MapSources<T>): T {
  const mapped: any = {}
  for (const key in sources) {
    mapped[key] = sources[key].map()
  }
  return mapped 
}


getMapped({a, b}).a // => should be 1
getMapped({a, b}).b // => should be 'str'
wclr reacted with thumbs up emoji wclr reacted with hooray emoji
All reactions
  • 👍 1 reaction
  • 🎉 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@wclr

Alex (wclr) commented Apr 6, 2017

Copy link
Copy Markdown

Any advice on how this can be accomplished a "functor" with two mapping methods :

  const a = {
    mapR: () => 1,
    mapT: () => true
  }

  const b = {
    mapR: () => 'str',
    mapT: () => false
  }

  type MapsTo<T, R> = {
    mapT: () => T,
    mapR: () => R
  }

  type MapSources<T, R> = {[K in keyof (T & R)]: MapsTo<T[K], R[K]> }


  function getMapped<T, R>(sources: MapSources<T, R>): { T: T, R: R } {
    const mapped: any = { T: {}, R: {}}
    for (const key in sources) {
      mapped.T[key] = sources[key].mapT()
      mapped.R[key] = sources[key].mapR()
    }
    return mapped
  }

  getMapped({ a, b }).R.a // => should be 1
  getMapped({ a, b }).R.b // => should be 'str'
  getMapped({ a, b }).T.a // => should be true
  getMapped({ a, b }).T.b // => should be false
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@spion

spion (spion) commented Apr 6, 2017 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Renamed in favour of (@whitecolor) you might want to try the gitter channel for typescript

Anyway, here is the solution: http://bit.ly/2od3xP5

The reason why the original doesn't work is because all the keys of T & R are not necessarily present in both T and R, so nothing is known about T[K] and R[K]. Moving the & operator to the argument level ensures that the argument is a source of both kinds of "maps"

wclr reacted with thumbs up emoji wclr reacted with hooray emoji
All reactions
  • 👍 1 reaction
  • 🎉 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bluebaroncanada bluebaroncanada mentioned this pull request Jul 14, 2017
SOLID properties, modularity, and knockout segregation knockout/tko#33
Closed
@olegdunkan olegdunkan mentioned this pull request Aug 18, 2017
Number index signature doesn't work with Readonly generic #17857
Closed
@virkt25 Taranveer Virk (virkt25) mentioned this pull request Oct 13, 2017
feat: mixin extension strongloop-archive/loopback4-extension-starter#7
Merged
@jtlapp Joe Lapp (jtlapp) mentioned this pull request Jan 12, 2018
Static type-checking for required properties in insertGraph()/upsertGraph() Vincit/objection.js#714
Closed
@pleerock Umed Khudoiberdiev (pleerock) mentioned this pull request Jan 26, 2018
Mapped type should take a function form as well #21421
Closed
@HecateDK minyillee (HecateDK) mentioned this pull request Mar 26, 2018
typescript vs flow HecateDK/LearningNotes#21
Open
@jcalz Joe Calzaretta (jcalz) mentioned this pull request Apr 24, 2018
Cannot map over intersection of string with string literal (e.g., "a" & string) #23651
Closed
@microsoft 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.

Reviewers

@sandersn Nathan Shively-Sanders (sandersn) sandersn approved these changes
+1 more reviewer
@mhegazy Mohamed Hegazy (mhegazy) mhegazy approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

20 participants

@ahejlsberg @jkillian @AlexGalays @alitaheri @HerringtonDarkholme @kourge @mhegazy @Lenne231 @stevekane @jods4 @BigDataSamuli @niieani @fredgalvao @PyroVortex @danielearwicker @aluanhaddad @zpdDG4gta8XKpMCd @electricessence @TobiaszCudnik @sandersn
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.