You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在映射类型函数参数中强制元组成员类型关系并保留类型信息?

问题描述

我定义了一套TypeScript类型,用来强制数组内的元组满足第二个成员是接收第一个成员类型作为参数的函数这一关系。但目前只有显式指定函数参数类型时,类型检查才会生效;如果不指定,函数的data参数会被推断为any,无法自动关联到元组第一个成员的类型。想知道有没有办法实现让函数参数类型自动从元组第一个成员的类型推断而来的效果。

现有实现代码

元组关系检查类型

export type TupleDataFn<Type>
    = Type extends [infer Data, infer Fn]
    ? Fn extends ((data: Data) => any)
        ? Type
        : never
    : never

数组映射类型(对所有成员应用检查)

export type ArrayOfTuples<A>
    = {[K in keyof A]: TupleDataFn<A[K]>}

测试函数

export const test = <H extends [any, any][]>(handler: ArrayOfTuples<H>) => {}

使用示例

test([
    // 显式指定类型时可正常工作
    ['explicit', (data: string) => {}],
    // 其余情况中,data参数类型为any而非推断自第一个成员的类型
    ['text', (data) => {}],
    [42, (data: string) => {}], // 此处本应报错,但因推断问题未触发检查
    [{ count: 10, data: "test"}, (data) => {}]
])
解决方案实现

要实现自动推断,需要调整泛型约束的方式,让TypeScript能从元组的第一个成员反向推导函数参数的类型。核心思路是用泛型元组类型描述单个元组的关系,再让数组由这类元组组成:

// 定义单个符合要求的元组类型:第一个元素为D,第二个为接收D的函数
type ValidTuple<D = unknown> = [D, (data: D) => void];

// 测试函数改为约束输入为ValidTuple的数组
export const test = <T extends ValidTuple[]>(handler: [...T]) => {}

修改后,TypeScript会自动为每个元组的函数参数推断出对应第一个成员的类型:

test([
    ['explicit', (data) => {}], // data自动推断为string
    ['text', (data) => {}],     // data自动推断为string
    [42, (data) => {}],         // data自动推断为number,若显式指定string会直接报错
    [{ count: 10, data: "test"}, (data) => {}] // data自动推断为{ count: number; data: string }
])

如果需要支持函数返回值不为void的场景,可调整ValidTuple的定义:

type ValidTuple<D = unknown, R = unknown> = [D, (data: D) => R];
原理说明

之前的实现用了映射类型ArrayOfTuples,但泛型约束H extends [any, any][]过于宽泛,TypeScript无法从第一个成员的类型反向推导函数参数。而直接用ValidTuple[]作为约束,TypeScript会逐个分析数组中的元组,将每个元组的第一个元素类型绑定到泛型D,从而自动推断出函数参数的类型。

内容的提问来源于stack exchange,提问作者Jarek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 16:23:10