如何编写一个foo: <A extends Foo|Fooo>(a:A) => AnotherType<A>
依赖于代码中的类型保护的通用函数来有条件地映射A
到AnotherType<A>
?
我已经尝试过了(从我的实际代码中简化):
interface Foo { _tag: 'foo'; /*fooProps*/ }
interface Fooo { _tag: 'fooo'; /*foooProps*/ }
const isFoo = (a:any): a is Foo { return a._tag === 'foo' }
interface Bar { _tag: 'bar'; /*fooProps transformed*/ }
interface Barr { _tag: 'barr'; /*foooProps transformed*/ }
type MapDomainToAnother<A extends Foo|Fooo> = A extends Foo ? Bar : Barr
现在我正在尝试使用泛型编写一个函数,该函数将采用 Foo|Fooo 并返回 Bar|Barr (但具有正确的类型“映射”:
const toDomainTwoViaMapper = <A extends Foo|Fooo>(a:A) => MapDomainToAnother<A> = a => {
if(isFoo(a)) {
// a is narrowed to `Foo & A`
return mapperA(a) // mapper: (a:Foo) => Bar
}
// a is "narrowed" to `A extends Foo|Fooo`
return mapperB(a) // mapper: (a:Fooo) => Barr // Error! Type hasn't been narrowed to Fooo so cannot be passed into mapperB!
}
我认为这个 typeguard 的行为不像预期的那样,因为A
extends DomainOne
。但是我需要使用泛型,以便我可以指定两个输入之一映射到两个输出之一,而不是任何一个输出类型!
const toDomainTwo = (a:Foo|Fooo) => isFoo(a) ? mapperA(a) : mapperB(a)
这导致类型(a:Foo|Fooo) => Bar|Barr
。非常不是我需要的。我实际上测试了这个
declare const x: Foo
const y = toDomainTwo(x) // type Bar|Barr! I want this to be type Bar