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

flow,如何从mixed类型转换为更具体的类型

  •  1
  • robC  · 技术社区  · 6 年前

    express定义的流类型libdef locals 作为一个对象 mixed 价值观。
    指定实际值类型会导致以下错误…这些特定类型应该如何注释?

    // From libdef
    type Locals = {
      [name: string]: mixed;
    }
    
    // Populated data
    const locals: Locals = {
      version: 1.2,
      resources: {
        a: "abc",
        b: "def"
      }
    };
    
    // Annotate the actual type
    const version: number = locals.version; // Error: mixed is incompatible with number
    const resources: {[string]: string} = locals.resources; // Error: mixed is incompatible with object type
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   James Kraus    6 年前

    一种方法是改进你收到的任何东西的类型,直到它符合你想要的形状。通常,我会制作一些基本的优化函数,并使用它们来构建更大的优化。

    ( Try )

    // From libdef
    type Locals = {
      [name: string]: mixed;
    }
    
    // Populated data
    const locals: Locals = {
      version: 1.2,
      resources: {
        a: "abc",
        b: "def"
      }
    };
    
    // The type you want
    type MyLocals = {
      version: number,
      resources: {
        // maybe this one is a map? idk
        [string]: string
      }
    }
    
    // Some basic refinement functions
    const refineString = (x: mixed): string => {
      if (typeof x === 'string') {
        return x 
      }
      throw new Error("Not a string")
    }
    
    const refineNumber = (x: mixed): number => {
      if (typeof x === 'number') {
        return x 
      }
      throw new Error("Not a number")
    }
    
    const refineObj = (x: mixed): {[string]: mixed} => {
      if (x instanceof Object) {
        return x 
      }
      throw new Error("Not an object")
    }
    
    // More type-specifc refinement functions
    const refineResources = (x: mixed): $ElementType<MyLocals, 'resources'> => {
      const anObj = refineObj(x)
      return Object.keys(anObj)
                   .reduce((acc, k) => Object.assign(acc, { [k]: refineString(anObj[k]) }), {})
    }
    
    const refineMyLocals = (x: mixed): MyLocals => {
      const {version, resources} = refineObj(x)
      return {
        version: refineNumber(version),
        resources: refineResources(resources)
      }
    }
    
    // Now use them to assert a type
    const myLocals: MyLocals = refineMyLocals(locals)
    const version: number = myLocals.version;
    const resources: {[string]: string} = myLocals.resources;
    

    或者,如果libdef在 flow-typed 文件夹,进去换一下libdef。它将使该类型特定于您的项目,但如果您不需要 [name: string]: mixed 在代码中键入其他地方。

        2
  •  1
  •   robC    6 年前

    看来这里唯一的办法就是 refinement 逻辑。

    if (typeof locals.version === "number") {
       const version: number = locals.version;
    }
    if (locals.resources instanceof Object) {
      const resources: {[string]: string} = locals.resources;
    }
    

    请注意,您也可以将数据本身转换为:

    const version: number = Number(locals.version);
    

    或定义新副本:

    const resources: {[string]: string} = {...locals.resources};