TypeScript 版本: 3.5.1
搜索词:
返回类型,泛型,约束,可分配,相关类型
代码
type XStr = {x:string};
type XNum = {x:number};
type U = XStr|XNum;
type Args = { str : XStr, num : XNum };
declare function foo<
ReturnT extends U,
ValueT extends ReturnT["x"]
> (
f : (args : Args) => ReturnT,
value : ValueT
) : void;
/*
Error as expected.
Type 'string | number' does not satisfy the constraint 'string'.
Type 'number' is not assignable to type 'string'.
*/
foo<XStr, string|number>(
(args:Args) => args.str,
""
);
//Inferred type, foo<XStr, string | number>
foo(
args => args.str,
//Expected: Error
//Actual: OK
"" as string|number
);
//Inferred type, foo<XStr, string>
foo(
//Added explicit type annotation to function params
(args:Args) => args.str,
/*
Error as expected.
Type 'string | number' does not satisfy the constraint 'string'.
Type 'number' is not assignable to type 'string'.
*/
"" as string|number
);
/////
/*
Error as expected.
Type '1' does not satisfy the constraint 'string'.
*/
foo<XStr, 1>(
(args:Args) => args.str,
1
);
//Inferred type, foo<XStr, 1>
foo(
args => args.str,
//Expected: Error
//Actual: OK
1
);
//Inferred type, foo<XStr, string>
foo(
//Added explicit type annotation to function params
(args:Args) => args.str,
/*
Error as expected.
Type '1' does not satisfy the constraint 'string'.
*/
1
);
预期行为:
我只是称之为 相关类型 ,因为它让我想起了SQL中的相关子查询。
ValueT
的约束类型取决于ReturnT
的类型。- 当
f
没有参数,或者所有参数都 显式 标注时,ValueT
被正确推断。 - 当
f
有 未 显式标注的参数时,ValueT
被错误地推断。 - 尝试显式设置无效的类型参数将按预期出错。
foo<XStr, string|number>
不被允许foo<XStr, 1>
不被允许
实际行为:foo<XStr, string|number>
在推断下被允许foo<XStr, 1>
在推断下被允许
Playground 链接:
Playground
相关问题:
32540 (评论)
#29133
一个不同且更复杂的示例,
14829 (评论)
[编辑]
有人能想出一个更好的名字吗?
我正在重写我的类型安全的SQL构建器库,它依赖于泛型函数的返回类型被正确推断。但似乎返回类型推断在很多意想不到的地方会出错。
匿名回调函数经常用于构建 WHERE
、 ORDER BY
、 GROUP BY
、 HAVING
、 JOIN
等子句。
由于泛型函数的返回类型推断不可靠,基本上对我来说是一个障碍=()
6条答案
按热度按时间lxkprmvk1#
从上述代码片段的行为以及由工具提示显示的推断类型来看,感觉像是有人忘记复制粘贴一些类型推断逻辑或其他东西。
例如,
Inferred type, foo<XStr, 1>
代码片段的类型被推断为foo<XStr, 1>
,但它的行为却像foo<U, 1>
。tyg4sfes2#
!@#$ YES!
我终于找到了一个解决方法!
Playground
这里的魔法是,
它将
ReturnT
转换为元组(2元组,在这个例子中),然后使用剩余参数。[编辑]
在花了周六的大部分时间思考解决方法后,我突然在随机回想起这里的评论后想到了这个主意。
32596 (评论)
我曾经提出过使用元组和剩余参数作为解决这个问题的可能方法(在该问题中有另一种更好的表达方式)。
[编辑]
等等...我刚刚意识到这个解决方法没有使用
ValueT
。我一定是太累了才会犯这种错误。Brb. 要修好它。(或者尝试)。
我的用例需要
ReturnT
和ValueT
,并在返回类型中对其进行操作。[编辑]
修复了使用
ValueT
的问题。[编辑]
算了吧。我试图将其适应到实际的用例中,但这个解决方法崩溃了。
首先,我想让我的
ReturnT
有选择成为联合类型的权利。所以,我不能让条件类型执行分布。
如果它不分布,我们就会回到推理问题的第一步。
Playground
ldioqlga3#
这更接近我的个人用例,
Playground
我需要允许返回一个联合类型并相应地处理它。
我的实际用例需要使用
UnionToIntersection<>
,尽管如此。0wi1tuuw4#
看起来使用
UnionToIntersection<>
会破坏它,NoInfer<>
也没有帮助。Playground
更好地重现了
UnionToIntersection<>
如何破坏这个解决方法,Playground
yxyvkwin5#
我忽略了除了OP之外的长篇大论。
为什么函数定义只是这个?
$x_{1a0b1}^{x}$
或者,似乎你需要一个非推断类型的参数使用操作符? $x_{1e0f1}^{x}$
zujrkrfu6#
我需要
arg
可能成为ReturnT["x"]
的子类型。在我的实际情况中,它用于返回类型(在我的 OP 中,返回类型为
void
以简化)。目前,所有尝试使用非推断类型的参数用法的解决方法都在这个用例中失效了。
该函数表示 SQL 中的一列。返回类型是该列的类型。
ValueT
表示该列的可能值。假设我们正在构建由库提供的查询,
假设该列的类型为
null|number
。如果我们添加这个
WHERE
子句,那么我们可以在不执行查询的情况下静态缩小查询中
myColumn
的类型为1
。