我如何改进这个通用 Box 函数的类型?

Posted

技术标签:

【中文标题】我如何改进这个通用 Box 函数的类型?【英文标题】:How I could improve the typing of this generic Box function? 【发布时间】:2021-04-25 10:53:45 【问题描述】:
function Box(x: any) 
  return 
    inspect: () => `Box($x)`,
    map: (f: (arg0: any) => any) => Box(f(x)),
    fold: (f: (arg0: any) => any) => f(x)
  


const expr = Box(8)
  .map((x: number) => x + 8)
  .map((x: any) => Number(x))
  .map((x) => Math.cos(x))

console.log(expr.fold((x: any) => x))

如何改进 Box 表达式的类型化?

【问题讨论】:

看看generics 你已经标记了这个 [typescript-generics],所以你似乎已经知道该怎么做了。您能否向我们展示您的尝试,或者解释一下您对使用泛型的不理解? 请注意 I cannot reproduce 你的 ESLint 警告;也许您的 IDE 配置有些奇怪?也许this 是你的问题? 每个帖子只问一个问题。我已经删除了关于 ESLint 的内容,您可能需要create a new question 来获取它(但请提供有关警告发生方式和位置的更多详细信息) 【参考方案1】:

“改进”Box 的类型有点模糊,但假设您希望 Box 跟踪它包含的值的类型,那么我将引入一个 generic 接口来表示预期行为:

interface Box<T> 
  inspect(): string;
  map<U>(f: (arg0: T) => U): Box<U>;
  fold<U>(f: (arg0: T) => U): U;

Box&lt;T&gt;inspect 方法总是产生string。它的map() 方法接受一个回调函数,将T 转换为其他类型U 并产生一个Box&lt;U&gt;,而fold 接受一个回调函数,将T 转换为其他类型U,并且只产生一个U.

然后您可以将名为 Box 的函数注释为接受 T 类型的值并返回 Box&lt;T&gt; 的泛型函​​数:

function Box<T>(x: T): Box<T> 
  return 
    inspect: () => `Box($x)`,
    map: f => Box(f(x)),
    fold: f => f(x)
  

注意如何删除Box 实现中的注释,因为它们是contextually typed 预期的Box&lt;T&gt; 方法参数类型。


然后,当您使用Box 时,您将看到编译器如何跟踪它是否持有numberstring(或其他任何东西),并且回调可以再次根据上下文键入,因此您可以省略他们的注释:

const expr = Box(Math.PI / 2) // Box(1.5707963267948966)
  .map(x => Math.cos(x)) // Box(6.123233995736766e-17)
  .map(x => x.toFixed(4)) // Box("0.0000")
  .map(x => Number(x)) // Box(0)

console.log(expr.fold(x => x).toFixed(2)) // "0.00"

如果你做错事,编译器会抱怨,比如把 string 当作 number

const badExpr = Box("Hello")
  .map(x => x.toFixed(2)); // error!
  // -------> ~~~~~~~
  // Property 'toFixed' does not exist on type 'string'.

Playground link to code

【讨论】:

理论上one doesn't even need the interface,但是TS推断的类型变得笨拙。 是的,递归匿名类型是?。

以上是关于我如何改进这个通用 Box 函数的类型?的主要内容,如果未能解决你的问题,请参考以下文章

slowfast 损失函数改进深度学习网络通用改进方案:slowfast的损失函数(使用focal loss解决不平衡数据)改进

我如何在函数体中使用通用类型

为啥我不能编写与 Box::new 相同类型的函数?

如何创建对各种整数类型通用的 is_prime 函数?

如何从“盒子”中获得拥有的价值?

用于测试对象类型的通用 Swift 函数