搜索词
类型别名参数推断上下文
建议
当值被分配/转换为该类型/接口时,类型别名(或接口)的类型参数应该能够被推断。
用例/示例
我的程序定义了一些常用的类型/接口,作为组件之间的契约。例如:
// type for an object holding a function + its inverse
type FunctionPair<T, U> = { apply(it: T): U, reverse(it: U): T };
然后,在整个程序中,我需要创建这些类型的对象。如果我有一个工厂函数(或者使用一个带有其构造函数的类),这并不糟糕:
function makeFunctionPair<T, U>(apply: (it: T) => U, reverse: (it: U) => T) {
return { apply, reverse } as FunctionPair<T, U>;
}
然而,我希望能够用字面量编写这些(简单的)领域对象,而不是使用工厂函数,然后用内联的类型注解/Assert向编译器发出类型信号:
const a: FunctionPair<string, () => string> = {
apply(it: string) { return () => it + "!!!"; },
reverse(it) { return it().slice(0, -3); }
}
然而,上面有点冗长,因为我不得不在类型注解中添加 apply
,而这似乎是可以推断出来的。我建议可以直接这样做:
/* FunctionPair type param values inferred contextually from the assigned object */
const a: FunctionPair = {
apply(it: string) { return () => it + "!!!"; },
reverse(it) { return it().slice(0, -3); }
}
这里有另一个例子:想象一个运行时使用效果作为数据的概念。用户将描述要执行的效果的对象发送到运行时,并提供一个回调函数来处理任何结果:
type EffectNamesWithReturnTypes = {
x: { status: 0 | 1 },
y: { changes: string[] },
};
type EffectDescriptor<T extends keyof EffectNamesWithReturnTypes> = {
name: T;
cb: (result: EffectNamesWithReturnTypes[T]) => void
}
它会写成这样就很好了:
const effect = <EffectDescriptor>{ name: "x", cb: (it) => it.status };
而不是这样:
const effect = <EffectDescriptor<"x">>{ name: "x", cb: (it) => it.status };
检查清单
我的建议满足以下准则:
- 这不会对现有的TypeScript/JavaScript代码造成破坏性的变化
- 这不会改变现有JavaScript代码的运行时行为
- 这可以在不根据表达式的类型发射不同的JS的情况下实现
- 这不是一个运行时特性(例如库功能、JavaScript输出的非ECMAScript语法等)
- 这个特性将与 TypeScript's Design Goals 的其他部分保持一致。
7条答案
按热度按时间9avjhtql1#
#26349
o4tp2gmn2#
感谢@fatcerberus。我早些时候看到了这个问题,但我的理解是它做了一些略有不同的事情,即:在TS可以推断所有参数或要求您指定所有参数的位置,#26349 会让用户指定一些参数并让其他参数被推断出来。在我谈论的这些情况下,尽管如此,对我来说并不清楚TS是否对这些参数有任何推断机制,这就是为什么它们都必须被指定的原因。
qlzsbp2j3#
关于这个想法,你有什么看法吗?
ftf50wuq4#
为了避免这对依赖默认类型参数的代码造成破坏性变化,它可能需要成为一个选择性的语法,例如
EffectDescriptor<infer>
。但由于这实际上是在函数调用推断过程中发生的,所以所有的机制都已经存在了。然而,在这里使用类型Assert的位置似乎有些问题。例如,你不想错过目标类型中的一个属性,但在这里很容易发生这种情况。拥有这样一个函数可以100%地用现有的语法实现用例,而不会引入意外地写出预期类型的超类型的潜在风险。
看起来你需要一个 #7481 的变体来避免向下转型的问题。
bxpogfeg5#
所有的机器都已经存在了,因为这个功能实际上是在函数调用推断过程中发生的。
很高兴听到这个消息!
可能需要使用一种选择性的语法,例如EffectDescriptor。
我同意。是否有必要考虑将这种语法与#26349的语法一起考虑?还是先选择#26349的语法,假设将其扩展到涵盖这种情况会很容易?(我看到很多人请求/期望#26349能够涵盖这一点。)
话虽如此,这里使用类型Assert的位置似乎有些问题。例如,你不想错过目标类型中的一个属性,但在这里很容易发生这种情况......似乎你需要一个#7481的变体来避免向下转型的问题。
好主意。即使这个功能只作为变量类型的注解工作,比如在我的
FunctionPair
示例中,我也会是一个快乐的用户。对我来说,支持在一个地方进行推断而不支持另一个地方的推断感觉有点不一致,而且这似乎是程序员的工作,确保他们对可能的向下转型感到舒适,这与推断是否应该发生的感觉是正交的。
话虽如此,我绝对希望最终的#7481语法与这里的理念兼容。
xxslljrj6#
这感觉就像是程序员的工作,确保他们对可能的向下转型感到舒适,这与推理是否应该发生是正交的。
哦,当然了,但如果必须在自动推断类型参数和未加防护的向下转型之间做出选择,那将是非常令人沮丧的,正是因为这两个关注点是正交的。
rqcrx0a67#
哦,当然可以,但是在自动推断类型参数和不加防护的向下转型之间进行选择会相当令人沮丧,这是因为这两个关注点是正交的。
对。我并不是主张将两者耦合在一起,这就是为什么我建议可以在可能进行向下转型的Assert中使用这种推断功能,或者在一个变量的类型注解中使用(它不会进行向下转型)。
示例:
而且,如果在未来引入一个非向下转型的类型Assert操作符( #7481 ),那么这个想法就是它也可以在使用和不使用推断的情况下使用。