Typescript 泛型判别并
我希望能够使用通用的。但是,它似乎不起作用: 示例代码(:Typescript 泛型判别并,typescript,discriminated-union,Typescript,Discriminated Union,我希望能够使用通用的。但是,它似乎不起作用: 示例代码(: 接口Foo{ 类型:“foo”; fooProp:string } 接口条{ 类型:'bar' barProp:数字 } 接口生成{ 项目:T; } 设func=(genericThing:genericThing)=>{ if(genericThing.item.type==='foo'){ genericThing.item.fooProp;//这可以工作,但genericThing的类型仍然是genericThing 让fooTh
接口Foo{
类型:“foo”;
fooProp:string
}
接口条{
类型:'bar'
barProp:数字
}
接口生成{
项目:T;
}
设func=(genericThing:genericThing)=>{
if(genericThing.item.type==='foo'){
genericThing.item.fooProp;//这可以工作,但genericThing的类型仍然是genericThing
让fooThing=genericing;
fooThing.item.fooProp;//错误!
}
}
我希望typescript能够认识到,由于我对generic项
属性进行了区分,因此generitching
必须是generitching
我猜这就是不被支持
另外,有点奇怪的是,在直接赋值之后,
fooThing.item
失去了辨别力。表达式generiching.item
被视为if
块中的Foo
。我认为它只有在将其提取到变量后才能工作(const item=genericThing.item
)。可能是最新版本TS的更好表现
这将启用模式匹配,如上的官方文档中的函数区域
,这在C#中实际上是缺失的(在v7中,像这样的开关
语句中仍然需要默认
情况)
事实上,奇怪的是,genericThing
仍然没有被区分(作为genericThing
而不是genericThing
),即使在if
块中,item
是Foo
!那么fooThing.item.fooProp;
的错误也不会让我感到惊讶
我想TypeScript团队还需要做一些改进来支持这种情况。问题
受歧视工会中的类型缩小受到若干限制:
不展开仿制药
首先,如果类型是泛型的,则泛型不会展开以缩小类型:缩小需要一个并集才能工作。例如,这不起作用:
let func = (genericThing: GenericThing<'foo' | 'bar'>) => {
switch (genericThing.item) {
case 'foo':
genericThing; // still GenericThing<'foo' | 'bar'>
break;
case 'bar':
genericThing; // still GenericThing<'foo' | 'bar'>
break;
}
}
最后一行出现了什么错误?仅仅从泛型中提取项,无论是在函数顶部还是通过在参数中进行分解,都会有什么不同吗?@jornsharpe打开typescript游乐场链接,您可以看到它。
fooProp在type上不存在…
oh,伙计……这个解决方案很粗糙!很好知道但这是可能的。我的解决方案只是针对嵌套对象编写代码,而不是尝试接受狭窄的泛型。例如:让我的函数接受Foo
(如果我需要做一些有区别的事情,则直接接受GenericThing
)it@NSjonas这也是一个选项:-)
let func = (genericThing: GenericThing<'foo' | 'bar'>) => {
switch (genericThing.item) {
case 'foo':
genericThing; // still GenericThing<'foo' | 'bar'>
break;
case 'bar':
genericThing; // still GenericThing<'foo' | 'bar'>
break;
}
}
let func = (genericThing: GenericThing<'foo'> | GenericThing<'bar'>) => {
switch (genericThing.item) {
case 'foo':
genericThing; // now GenericThing<'foo'> !
break;
case 'bar':
genericThing; // now GenericThing<'bar'> !
break;
}
}
let func = (genericThing: GenericThing<{ type: 'foo' }> | GenericThing<{ type: 'bar' }>) => {
switch (genericThing.item.type) {
case 'foo':
genericThing; // still GenericThing<{ type: 'foo' }> | GenericThing<{ type: 'bar' }>)
genericThing.item // but this is { type: 'foo' } !
break;
case 'bar':
genericThing; // still GenericThing<{ type: 'foo' }> | GenericThing<{ type: 'bar' }>)
genericThing.item // but this is { type: 'bar' } !
break;
}
}
function isOfType<T extends { type: any }, TValue extends string>(
genericThing: GenericThing<T>,
type: TValue
): genericThing is GenericThing<Extract<T, { type: TValue }>> {
return genericThing.item.type === type;
}
let func = (genericThing: GenericThing<Foo | Bar>) => {
if (isOfType(genericThing, "foo")) {
genericThing.item.fooProp;
let fooThing = genericThing;
fooThing.item.fooProp;
}
};