如何将身份函数严格键入为特定变换?
How to strictly type an identity function as a specific transform?
我如何定义一个函数类型 transform<I, O>
接受类型 I 的输入和 return 类型 O 的输出,然后定义一个 identity
函数作为一个特定的实现transform
?
例如
type transform<I, O> = (input: I) => O;
const identity = // ...
这样我就可以定义一个函数
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;
}, {});
mapToObject
函数应该采用 Map
和 transformValue
函数并将地图转换为简单的 JS 对象,将 transformValue
应用于地图中的每个值。 transformValue
应默认为 identity
函数 v => v
。
身份函数映射 any
到 any
有效,尽管我对严格类型化的解决方案很感兴趣。
您可以将泛型参数放入箭头函数或常规函数中
type transform<I, O> = (input: I) => O;
const identity = <I, O> (input: I) => {
return null;
}
//Or
const identity2 = function <I, O> (input: I) {
return null;
}
const mapToObject = <K extends string, V, O>(
map: Map<K, V>,
transformValue: transform<V, O> = identity
) => Array.from(map.entries()).reduce((obj, [key, val]) => {
obj[key] = transformValue(val);
return obj;
}, <{ [index: string]: O }>{});
只有一种合理的方法来输入恒等函数,这并不奇怪
const identity = <T>(t: T) => t;
但是严格类型的标识函数不能分配给任意转换 - 编译器知道它 returns 与接收到的类型相同,所以你为 mapToObject
键入不一致 - 结果类型是什么当你称它为
mapToObject<string, number, Date>(new Map<string, number>())
- 由于它使用默认的身份转换,结果对象必须包含数字
- 但是您明确提供了第三个泛型参数,因此生成的对象必须包含
Dates
这需要表示为依赖类型 - 结果对象的类型取决于是给出转换参数还是使用默认值。在 TypeScript 中,您可以使用 overloading function declarations:
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;
}, {});
}
由于在实现中根本不使用实际值类型,它可以作为空对象类型给出{}
,它与 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
结果类型按预期推断:
const o1 = mapToObject(new Map<string, number>())
// {[n: string]: number}
const o2 = mapToObject(new Map<string, number>(), n => new Date(n))
// {[n: string]: Date}
我如何定义一个函数类型 transform<I, O>
接受类型 I 的输入和 return 类型 O 的输出,然后定义一个 identity
函数作为一个特定的实现transform
?
例如
type transform<I, O> = (input: I) => O;
const identity = // ...
这样我就可以定义一个函数
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;
}, {});
mapToObject
函数应该采用 Map
和 transformValue
函数并将地图转换为简单的 JS 对象,将 transformValue
应用于地图中的每个值。 transformValue
应默认为 identity
函数 v => v
。
身份函数映射 any
到 any
有效,尽管我对严格类型化的解决方案很感兴趣。
您可以将泛型参数放入箭头函数或常规函数中
type transform<I, O> = (input: I) => O;
const identity = <I, O> (input: I) => {
return null;
}
//Or
const identity2 = function <I, O> (input: I) {
return null;
}
const mapToObject = <K extends string, V, O>(
map: Map<K, V>,
transformValue: transform<V, O> = identity
) => Array.from(map.entries()).reduce((obj, [key, val]) => {
obj[key] = transformValue(val);
return obj;
}, <{ [index: string]: O }>{});
只有一种合理的方法来输入恒等函数,这并不奇怪
const identity = <T>(t: T) => t;
但是严格类型的标识函数不能分配给任意转换 - 编译器知道它 returns 与接收到的类型相同,所以你为 mapToObject
键入不一致 - 结果类型是什么当你称它为
mapToObject<string, number, Date>(new Map<string, number>())
- 由于它使用默认的身份转换,结果对象必须包含数字
- 但是您明确提供了第三个泛型参数,因此生成的对象必须包含
Dates
这需要表示为依赖类型 - 结果对象的类型取决于是给出转换参数还是使用默认值。在 TypeScript 中,您可以使用 overloading function declarations:
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;
}, {});
}
由于在实现中根本不使用实际值类型,它可以作为空对象类型给出{}
,它与 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
结果类型按预期推断:
const o1 = mapToObject(new Map<string, number>())
// {[n: string]: number}
const o2 = mapToObject(new Map<string, number>(), n => new Date(n))
// {[n: string]: Date}