0

如何编写一个foo: <A extends Foo|Fooo>(a:A) => AnotherType<A>依赖于代码中的类型保护的通用函数来有条件地映射AAnotherType<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
4

0 回答 0