如何约束函数的入参间的关系?

type ITrack<T extends Record<any, (...args: any[]) => void>> = (trackName: keyof T, ...args: Parameters<T[keyof T]>) => void;

interface ITrackMethods {
  trackA: (data: { a: string }, options: { force?: boolean }) => void;
  trackB: (data: { b: number }) => void;
}

export const track: ITrack<ITrackMethods> = (trackName, trackData) => {
  if (trackName === 'trackA') {
    // 希望这里 trackData 的类型为 Parameters<ITrackMethods['trackA']>[0]
    console.log(trackData.a);
  } else if (trackName === 'trackB') {
    // 希望这里 trackData 的类型为 Parameters<ITrackMethods['trackB']>[0]
    console.log(trackData.b)
  }
};

希望能够实现一个工具类型 ITrack,入参之间存在类型约束,可自动推导出类型。
但是上方实现由多处报错。
image.png

阅读 2.2k
2 个回答

合在一起才好收窄类型

type Magic<T, K = keyof T> = K extends keyof T ? T[K] extends (...args: any[]) => void ? {
  trackName: K;
  trackData: Parameters<T[K]>[0];
} : never : never

export const track = ({ trackData, trackName }: Magic<ITrackMethods>) => {
  if (trackName === 'trackA') {
    // 希望这里 trackData 的类型为 Parameters<ITrackMethods['trackA']>[0]
    console.log(trackData.a);
  } else if (trackName === 'trackB') {
    // 希望这里 trackData 的类型为 Parameters<ITrackMethods['trackB']>[0]
    console.log(trackData.b)
  }
};
interface ITrackMethods {
    trackA: (data: { a: string }, options: { force?: boolean }) => void;
    trackB: (data: { b: number }) => void;
}

type ITrackParams<T> = {
    [K in keyof T]: T[K] extends (...args: any) => void ? [key: K, ...args: Parameters<T[K]>] : never
}[keyof T]

const track = ([trackName, trackData]: ITrackParams<ITrackMethods>) => {
    if (trackName === 'trackA') {
        // string
        console.log(trackData.a);
    } else if (trackName === 'trackB') {
        // number
        console.log(trackData.b)
    }
};
logo
Microsoft
子站问答
访问
宣传栏