Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

lets imagine type T:

type T = {
  prop1: (s: S) => T1,
  prop2: (s: S) => T2,
  prop3: (s: S) => T3,
}

and now lets imagine type W

type W = (s: S) => {
    prop1: T1,
    prop2: T2,
    prop3: T3,
}

its easy to write a function that maps T to W by hand,

is it possible to write generic type sefe version of it in typescript?

function x(t: T): W {
  return funtion(s: S) {
    prop1: t.prop1(s),
    prop2: t.prop2(s)
    prop3: t.prop3(s)
  }
}

what kind of feature language is missing to facilitate this, something like higher order generic types?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
297 views
Welcome To Ask or Share your Answers For Others

1 Answer

You can indeed write a generic version of this in TypeScript:

function x<S, V>(t: {[K in keyof V]: (s: S) => V[K]}): (s: S) => V {
  return function(s: S): V {
    const ret = {} as V;
    Object.keys(t).forEach((k: keyof V) => {
      ret[k] = t[k](s);
    })
    return ret;
  }
} 

const xSpecific: (t: T) => W = x; // okay

Note that V is the return type of your W function. (So W is essentially the same as (s: S) => V.) And the input to x is a mapped type corresponding to T: it has the same keys as V, but its values are functions from S to the corresponding properties of V.

You can get away with having the function input being a mapped type and the output being an unmapped one because TypeScript supports inference from mapped types. Otherwise you'd need something like the proposed "extended typeof" feature to derive W from T generically. (This might be the missing language feature to which you're alluding.)

As for the implementation, I'm looping over the keys of t and applying each function t[k] to the input s.

And xSpecific is the same as x narrowed to the particular T and W types you posted. This compiles because TypeScript recognizes that the generic x is compatible.


Now for the caveats and fine print. Unfortunately, the compiler isn't able to reliably infer the type of S from x directly. If you just call the generic x() with a T input, you get this:

declare const t: T;
const w = x(t); // (s: {}) => { prop1: T1; prop2: T2; prop3: T3; }

The w is not exactly a W... it accepts any input, not just an S. If you really need to narrow the type of input, you'll have to do it yourself by manually specifying the generic parameters:

const w = x<S, {prop1: T1, prop2: T2, prop3: T3}>(t);

which is ugly, or narrowing the resulting w manually by assertion or annotation:

const w: W = x(t);

Anyway, hope that helps. Good luck!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...