打字稿中类型的通用映射

时间:2018-01-06 18:52:03

标签: typescript generics type-conversion type-safety

让我们想象出类型T:

t,Algorithm,Values
0,alg1,0.000000000000
0,alg2,0.000000000000
0,alg3,0.000000000000
0,alg4,0.000000000000
0,alg5,0.000000000000

100,alg1,0.950000000000
100,alg2,0.950000000000
100,alg3,0.950000000000
100,alg4,0.000000000147
100,alg5,0.000000000000

200,alg1,0.950000000005
200,alg2,0.950000000000
200,alg3,0.950000001250
200,alg4,0.004578701861
200,alg5,0.000000182645

250,alg1,0.950000259280
250,alg2,0.950000000000
250,alg3,0.950000400517
250,alg4,0.219429576450
250,alg5,0.000199361725

300,alg1,0.950314820965
300,alg2,0.950000000000
300,alg3,0.950037201876
300,alg4,0.824669958806
300,alg5,0.012390843342

400,alg1,0.992274938722
400,alg2,0.950000000000
400,alg3,0.959167637150
400,alg4,0.936487596777

400,alg5,0.603221722035
500,alg1,0.998314400000
500,alg2,0.998334835568
500,alg3,0.995747486022
500,alg4,0.978514678505
500,alg5,0.917973600000

600,alg1,0.998314400000
600,alg2,0.999100000000
600,alg3,0.999118983394
600,alg4,0.998040800000
600,alg5,0.917973600000

现在让我们假设输入W

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

很容易编写一个用手将T映射到W的函数,

是否可以在打字稿中编写通用类型的sefe版本?

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

缺少什么样的特征语言来促进这一点,比如更高阶的泛型类型?

1 个答案:

答案 0 :(得分:1)

你确实可以在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

请注意,VW函数的返回类型。 (所以W(s: S) => V基本相同。)x的输入是与T对应的mapped type:它具有与V相同的键{1}},但其值是从SV的相应属性的函数。

由于TypeScript支持inference from mapped types,因此您可以将函数输入作为映射类型而输出是未映射的类型。否则,您需要the proposed "extended typeof" feature之类的内容来一般从W派生T。 (这可能是您提到的缺失语言功能。)

至于实现,我循环遍历t的键并将每个函数t[k]应用于输入s

xSpecific与您发布的特定xT类型缩小的W相同。这是编译因为TypeScript识别通用x是兼容的。

现在进行警告和细则。不幸的是,编译器无法直接从S可靠地推断出x的类型。如果您只是使用x()输入调用通用T,则可以获得:

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

w不完全是W ...它接受任何输入,而不只是S。如果你真的需要缩小输入类型,你必须自己手动指定通用参数:

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

这是丑陋的,或者通过断言或注释手动缩小结果w

const w: W = x(t);

无论如何,希望有所帮助。祝你好运!