代码之家  ›  专栏  ›  技术社区  ›  Yakimych

Typescript判别联合允许无效状态

  •  6
  • Yakimych  · 技术社区  · 6 年前

    Discriminated Union 要在异步加载数据时对一个相当常见的场景进行建模,请执行以下操作:

    type LoadingState = { isLoading: true; }
    type SuccessState = { isLoading: false; isSuccess: true; }
    type ErrorState =   { isLoading: false; isSuccess: false; errorMessage: string; }
    
    type State = LoadingState | SuccessState | ErrorState;
    

    const testState: State = {
        isLoading: true,
        isSuccess: true,
        errorMessage: "Error!"
    }
    

    我想这里会出错。我是否遗漏了什么,或者在某种程度上误用了类型定义?

    1 回复  |  直到 6 年前
        1
  •  22
  •   Titian Cernicova-Dragomir    4 年前

    这是一个过度财产检查对工会工作方式的问题。如果将对象文字赋给了联合类型的变量,则如果某个属性存在于 任何 工会成员。如果我们不认为多余的属性是一个错误(并且除了对象文字外,它们不被认为是一个错误),那么您指定的对象文字可以是的一个实例 LoadingState (一个例子) isLoading 设置为 true

    为了避免这种不受欢迎的行为,我们可以向 加载状态 使对象文字与 加载状态

    type LoadingState = { isLoading: true; isSuccess?: never }
    type SuccessState = { isLoading: false; isSuccess: true; }
    type ErrorState =   { isLoading: false; isSuccess: false; errorMessage: string; }
    
    type State = LoadingState | SuccessState | ErrorState;
    
    const testState: State = { // error
        isLoading: true,
        isSuccess: true,
        errorMessage: "Error!"
    }
    

    type LoadingState = { isLoading: true; }
    type SuccessState = { isLoading: false; isSuccess: true; }
    type ErrorState =   { isLoading: false; isSuccess: false; errorMessage: string; }
    
    type UnionKeys<T> = T extends T ? keyof T : never;
    type StrictUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
    type StrictUnion<T> = StrictUnionHelper<T, T>
    
    type State = StrictUnion< LoadingState | SuccessState | ErrorState>
    
    const testState: State = { // error
        isLoading: true,
        isSuccess: true,
        errorMessage: "Error!"
    }