首页 文章

Flowtype - 编码另一种类型的类型细化

提问于
浏览
1

在Flow中,使用disjoint union类型,我可以使用type refinement根据某个属性选择性地定位联合的子集 .

如果我想将所有代码放在一个switch语句中,那就太棒了 . 但是,如果我想将代码拆分为函数,我不知道如何将类型细化“编码”为类型声明,以便流程“知道”在这些函数中进行了细化 .

在这里's an example of what I' d喜欢这样做 - 它可以在流动操场here上找到 .

是否有(非手动,非冗余)方式来声明 Thing 的子类型或其他语法,以对类型细化进行编码,以便我可以'pass it on'进入 printThingOfTypeA 函数?

type Thing = 
  | { type: 'a', a: 1 }
  | { type: 'a', a: 2 }
  | { type: 'b', b: 3 }
  | { type: 'b', b: 4 }
  | { type: 'c', c: 5 }
  | { type: 'c', c: 6 }

function printThing (thing: Thing): void {
  switch (thing.type) {
    case 'a': console.log(thing.a); break;
    // fails, can't be a c field if type is 'b'
    case 'b': console.log(thing.c); break;
    // fails, can't be an a field if type is 'c'
    case 'c': console.log(thing.a); break;
  }
}

printThing({ type: 'a', a: 1 })

// what type do I give thingOfTypeA so that flow refines Thing
// to only the options with type 'a', like in the case 'a': statement?
//
// e.g. Hypothetical syntax: (thingOfTypeA: Thing extends { type: 'a' })
//
function printThingOfTypeA (thingOfTypeA: Thing) {
  // this is fine as all have a type
  console.log('type: ' + thingOfTypeA.type)
  // how can this 'know' that I've passed a thing of type 'a'
  // so that it doesn't fail?
  console.log('a: ' + thingOfTypeA.a)
}

1 回答

  • 0

    您是否考虑将 Thing 的类型拆分为三个定义?

    Try

    type ThingA =
      | { type: 'a', a: 1 }
      | { type: 'a', a: 2 }
    
    type ThingB =
      | { type: 'b', b: 3 }
      | { type: 'b', b: 4 }
    
    type ThingC =
      | { type: 'c', c: 5 }
      | { type: 'c', c: 6 }
    
    type Thing = 
      | ThingA
      | ThingB
      | ThingC
    
    printThing({ type: 'a', a: 1 })
    
    // what type do I give thingOfTypeA so that flow refines Thing
    // to only the options with type 'a', like in the case 'a': statement?
    //
    // e.g. Hypothetical syntax: (thingOfTypeA: Thing extends { type: 'a' })
    //
    function printThingOfTypeA(thingOfTypeA: ThingA) {
      // this is fine as all have a type
      console.log('type: ' + thingOfTypeA.type)
      // how can this 'know' that I've passed a thing of type 'a'
      // so that it doesn't fail?
      console.log('a: ' + thingOfTypeA.a)
    }
    

    这样你的函数可以接受更具体的 ThingA ,而其他代码可以使用更通用的 Thing .

    或者,如果你可以't break it apart, you can just write a type describing what you need in the function param, but then you can'传递任何 Thing ,因为那个东西可能没有必要的属性:

    Try

    type Thing = 
      | { type: 'a', a: 1 }
      | { type: 'a', a: 2 } 
      | { type: 'b', b: 3 }
      | { type: 'b', b: 4 }
      | { type: 'c', c: 5 }
      | { type: 'c', c: 6 }
    
    const a1 = {type: 'a', a: 2}
    const a2: Thing = {type: 'a', a: 1}
    
    function printThingOfTypeA(thingOfTypeA: {type: 'a', a: number}) {
      console.log('type: ' + thingOfTypeA.type)
      console.log('a: ' + thingOfTypeA.a)
    }
    
    printThingOfTypeA(a1)
    printThingOfTypeA(a2) // Error
    

相关问题