我如何改进这个通用 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<T>
的inspect
方法总是产生string
。它的map()
方法接受一个回调函数,将T
转换为其他类型U
并产生一个Box<U>
,而fold
接受一个回调函数,将T
转换为其他类型U
,并且只产生一个U
.
然后您可以将名为 Box
的函数注释为接受 T
类型的值并返回 Box<T>
的泛型函数:
function Box<T>(x: T): Box<T>
return
inspect: () => `Box($x)`,
map: f => Box(f(x)),
fold: f => f(x)
注意如何删除Box
实现中的注释,因为它们是contextually typed 预期的Box<T>
方法参数类型。
然后,当您使用Box
时,您将看到编译器如何跟踪它是否持有number
或string
(或其他任何东西),并且回调可以再次根据上下文键入,因此您可以省略他们的注释:
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解决不平衡数据)改进