如何严格输入恒等函数作为特定变换?

Daw*_*son 4 generics transformation typescript

如何定义一个transform<I, O>接受类型 I 的输入并返回类型 O 的输出的函数类型,然后将函数定义identity为 a 的特定实现transform

例如

type transform<I, O> = (input: I) => O;

const identity = // ...
Run Code Online (Sandbox Code Playgroud)

这样我就可以定义一个函数

const mapToObject = <K, V, O>(
  map: Map<K, V>, 
  transformValue: transform<V, O> = identity
) => Array.from(map.entries()).reduce((obj, [key, val]) => {
  obj[key] = transformValue(value);
  return obj;
}, {});
Run Code Online (Sandbox Code Playgroud)

mapToObject函数应该采用MapandtransformValue函数并将映射转换为简单的 JS 对象,应用于transformValue映射中的每个值。transformValue应默认为identity函数v => v.

尽管我对严格类型的解决方案感兴趣,但恒等函数映射any是有效的。any

art*_*tem 5

只有一种合理的方法来输入恒等函数,这并不奇怪

const identity = <T>(t: T) => t;
Run Code Online (Sandbox Code Playgroud)

但是严格类型的恒等函数不能分配给任意转换 - 编译器知道它返回与收到的类型相同的类型,因此您的输入mapToObject不一致 - 当您调用它时结果类型是什么

   mapToObject<string, number, Date>(new Map<string, number>())
Run Code Online (Sandbox Code Playgroud)
  • 由于它使用默认的恒等变换,因此结果对象必须包含数字
  • 但您明确提供了第三个通用参数,因此结果对象必须包含Dates

这需要表示为依赖类型 - 结果对象的类型取决于是否给出变换参数或使用默认值。在 TypeScript 中,您可以通过重载函数声明来做到这一点:

function mapToObject<K, V>(map: Map<K, V>)
    : { [n: string]: V };
function mapToObject<K, V, O>(map: Map<K, V>, transformValue: transform<V, O>)
    : { [n: string]: O };
function mapToObject<K, V, O>(map: Map<K, V>, transformValue?: transform<V, O>)
    : { [n: string]: {} } 
{
    const transform: (v: V) => {} = transformValue || identity; 
    return Array.from(map.entries()).reduce((obj, [key, val]) => {
        obj[key.toString()] = transform(val) ;
        return obj;
    }, {});
}
Run Code Online (Sandbox Code Playgroud)

由于实际值类型根本没有在实现中使用,因此它可以作为空对象类型给出{},它与 V 和 O 类型兼容(您可以使用联合类型V | O,因为它也是兼容的,但它更冗长并且可以让您购买这里没有什么)

通过这些声明,编译器可以检测到不一致的用法:

// error: Expected 1-2 arguments, but got 1 
mapToObject<string, number, Date>(new Map<string, number>())

mapToObject<string, number>(new Map<string, number>()) // ok
mapToObject<string, number, Date>(new Map<string, number>(), n => new Date(n)) //ok
Run Code Online (Sandbox Code Playgroud)

结果类型按预期推断:

const o1 = mapToObject(new Map<string, number>())
 // {[n: string]: number}

const o2 = mapToObject(new Map<string, number>(), n => new Date(n))
 //  {[n: string]: Date}
Run Code Online (Sandbox Code Playgroud)