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

确保函数签名中的类型安全:匹配值

  •  1
  • user23505545  · 技术社区  · 2 年前

    我想设置一个具有格式化方法的配置对象。

    我似乎无法对format方法的参数进行类型检查

    export interface Config<D, ConfigId extends keyof D> {
      id: ConfigId
      format?: (value: D[ConfigId]) => any
    }
    
    type Data = {testA: number, testB: string}
    
    const configObjs: readonly Config<{testA: number, testB: string}, keyof Data>[] = [
      {
        id: 'testA',
        format: (value) => {
          return value
        },
      },
    
    ]
    

    我已经试了很多次了。什么都做不出来。

    我希望上面例子中的format方法中的arg只能是一个数字。

    这是一个打字游戏场idk它们能持续多久,但是: https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBASwHY2FAZgQwMbDgYQiXQQHMAeAEQBoCiTSBJAEzlFSWYGc4BrYAJ4R0cSgD44AbwBQcRMwBcdYmRay46aAFtMMAPxKAFADdMAGwCuwJZQDahFU2YBdAJRwAvBMxIB0gL7S0jACYHiUupieUqhcMACCSkgWWgBGaLSxMABCSnFQyKSB0thEcXCljgDyqQBWXEpQwJjMRGYCygzkklmJcMlpGXBZuXD5hf60-EIiETCYYrbO0bbqMnJyCIpwAOS9O9TqcppQOjBGppbA7l5SRxtNMBZQSHCXVveT6l-SztJAA

    1 回复  |  直到 2 年前
        1
  •  1
  •   jcalz    2 年前

    你想要 Config<D, K> 成为 分配的 unions 在里面 K 。这意味着,例如, Config<D, K1 | K2 | K3> 应该扩展到 Config<D, K1> | Config<D, K2> | Config<D, K3> ,其中每个键都在 K 具有自己的对象类型,因此 id 和 value 将在每个工会成员中匹配。但现在你得到的是一个带有并集的单个对象类型 身份证件 和一个联盟 价值 callback参数,它混合而不是匹配。

    有几种方法可以将非分配类型转换为分配类型。当你分发 钥匙 或 类键类型 ,我通常使用所谓的 分布式对象类型 正如在中创造的 microsoft/TypeScript#47109 。它包括制作 mapped type 越过钥匙,然后立即 indexing into 它使用键来获得并集结果。所以如果 F<K> 在中是非分配的 K ,你可以写 {[P in K]: F<P>}[K]} 以获得分发版本。

    以你为例,这看起来像

    type Config<D, K extends keyof D> = { [P in K]: {
      id: P
      format?: (value: D[P]) => any
    } }[K]
    

    请注意,这是一个 type alias 而不是 interface ,因为接口不能是并集。

    让我们测试一下:

    type Data = { testA: number, testB: string }
    
    type Test = Config<Data, keyof Data>;
    /* type Test = {
        id: "testA";
        format?: ((value: number) => any) | undefined;
    } | {
        id: "testB";
        format?: ((value: string) => any) | undefined;
    } */
    

    看起来不错。现在 Config<Data, keyof Data> 是 discriminated union 你想要的形状,所以里面

    const configObjs: readonly Config<Data, keyof Data>[] = [
      {
        id: 'testA',
        format: (value) => {
          //     ^?(parameter) value: number
          return value
        },
      },   
    ]
    

    一切正常,因为编译器可以通过判别式来判别并集 身份证件 财产是 "testA" ,以及 价值 回调参数为 contextually 推断为 number .

    Playground link to code