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

为什么索引到映射类型会使类型保持狭窄?

  •  0
  • dwjohnston  · 技术社区  · 3 年前

    这个问题是这个奇妙答案的后续:

    https://stackoverflow.com/a/64753409/1068446

    我想知道的是 为什么? 映射类型中的索引是否有效?

    举个例子:

    type MyData = {
      a: {
        alpha: string; 
      }; 
      b: {
        beta: number; 
      }
    }
    
    type NotNarrowPayload<T extends MyData> = {
      key: keyof T; 
      fn: (data: T[keyof T]) => void; 
    }
    
    type NarrowDataPayload<T extends MyData> = {
      [K in keyof T]: {
        key: K; 
        fn: (data: T[K]) => void; 
      }
    }[keyof T]; 
    
    
    function acceptsMTVTFunction<T extends MyData>(baseData: T,fn: NotNarrowPayload<T>) {
    
    }
    
    
    function acceptsMTVTFunction2<T extends MyData>(baseData: T,fn: NarrowDataPayload<T>) {
    
    }
    
    
    
    acceptsMTVTFunction(
        {
        a: {
          alpha: "a"
        }, 
        b: {
          beta: 99
        },
      }, 
      {
        key: "a", 
        fn: (data) => {
          // TypeScript doesn't match the key to the value type, and this makes sense. 
          // (parameter) data: {
          //     alpha: string;
          // } | {
          //     beta: number;
          // }
      }
    }
    ); 
    
    
    
    acceptsMTVTFunction2(
      {
        a: {
          alpha: "a"
        }, 
        b: {
          beta: 99
        },
      }, 
      {
        key: "a", 
        fn: (data) => {
          //       (parameter) data: {
          //     alpha: string;
          // }
      }
    }
    );
    

    TypeScript Playground

    现在,说清楚一点——我理解第一种方法 工作

    但我不明白为什么第二种方法 工作

    如果我们仔细看一下:

    type NarrowDataPayload<T extends MyData> = { // We're declaring an object 
      [K in keyof T]: { // For each key in T, it will have a property
        key: K; // And these values will depend on T and K 
        fn: (data: T[K]) => void; 
      }
    }[keyof T]; // But only keep the types accessible by keyof T. 
    

    问题是,TypeScript怎么知道我们在这里使用的键类型是“a”而不是“b”。

    1 回复  |  直到 3 年前
        1
  •  0
  •   dwjohnston    3 年前

    打字稿 了解如何区分键类型,了解 NarrowDataPayload 决议:

    const data = {
      a: {
        alpha: "a"
      },
      b: {
        beta: 99
      }
    }; 
    
    
    type A = NarrowDataPayload<typeof data>; 
    
    // type A = {
    //     key: "a";
    //     fn: (data: {
    //         alpha: string;
    //     }) => void;
    // } | {
    //     key: "b";
    //     fn: (data: {
    //         beta: number;
    //     }) => void;
    // }
    
    

    这是工会式的。

    类型映射技巧中的索引所做的是保持 key fn 保持一致——这就是您从早期方法中得到的改进。