TypeScript版本:3.9.0-dev.20200319
搜索词:discrimant tagged union assignable
代码
一个简化的复现示例,基于实际代码:
interface A { x: number }
interface B { x: string }
interface U$A { kind: 'A', body: A }
interface U$B { kind: 'B', body: B }
interface U$null { kind: 'C' | 'D', body?: undefined }
type U = U$A | U$B | U$null;
declare function foo(u: U): void;
foo({kind: 'A', body: { x: 42 }}); // OK
foo({kind: 'B', body: { x: 42 }}); // Not OK
预期行为:
第二个 x: 42
得到一个波浪线和错误 Type 'number' is not assignable to type 'string'.
实际行为:
第二个 foo
调用的整个参数得到一个波浪线和错误:
参数类型为 '{ kind: "B"; body: { x: number; }; }' 的错误,无法分配给 U 类型的参数。类型 '{ kind: "B"; body: { x: number; }; }' 无法分配给 U$null 类型。属性 'kind' 的类型不兼容。类型 '"B"' 无法分配给类型 '"C" | "D"'。
我希望通过检查 kind
属性首先缩小参数的类型为 U$B
。目前,当涉及的类型的形状变大时,开发者用户体验并不理想,而且很难弄清楚哪个属性出错(在我的实际情况中,联合有250+个成员,错误信息难以理解)。
注意事项
如果将 interface B
中的 x
更改为 y
,错误消息会出现得很好。
此外,如果我注解掉对 U$null
的两个引用,我会得到一个不同的(但也是可接受的)错误。
Playground链接:https://www.typescriptlang.org/v2/en/play?ts=next#code/JYOwLgpgTgZghgYwgAgILIN7IB4C5kgCuAtgEbTIC+AUKJLIigEKY74DOYUoA5ldbXDR4SZAFUAJOiwBrUABN8AclRKANMlIB7eQE986GnWGNxElrIXKm6zTv3IWRoQ1GSiAGw+s5IRciUAYSVkAB8AgBFbbT0AfnxCPwgYUAh5fmowXQAHFDFkAF4zdHDJFlKJTw8AbgF5CAQPOCgUGESEMGAtEGQYLS0ACkJ8MQBKfAA3LWB5Wuo+wYxffxVo+3wsPGQAFgAmKkpR2oWBpasAmw0Yh038PYOj6iA
相关问题
似乎没有与此完全相同的问题(凭直觉猜测)。
3条答案
按热度按时间uhry853o1#
提供更好的错误信息的逻辑取决于在目标类型中找到一个具体的判别标准,我们不认为联合是一个有效的判别标准——换句话说,
U$null
是在这里出问题的地方,如果用两种不同类型的扩展形式写出来会更好。wwwo4jvm2#
感谢RyanCavanaugh的建议,我尝试了扩展
U$null
,但仍然发现判别式没有先应用:参数类型为'{ kind: "B"; body: { x: number; }; }'的参数不能分配给类型为'U'的参数。类型'{ kind: "B"; body: { x: number; }; }'不能分配给类型'U$D'。属性'kind'的类型不兼容。类型'"B"'不能分配给类型'"D"'。
Playground链接
ldioqlga3#
我在使用
useAsyncFn
from react-use时遇到了这个问题:Playground链接
错误信息:
预期的错误信息应该是类似于: