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

如何在TypeScript中结合泛型使用元组实现类型安全映射

实现类型安全的泛型映射对象(仅定义一次键值对)

我想要实现一个类型安全的映射对象,只需要定义一次键值对。目前已经完成了以下代码:

const myPropTuple = [
    [0, "cat"],
    [1, "dog"],
    [2, "bird"]
] as const;

type TMyPropKey = TInnerTupple<typeof myPropTuple>[0];
type TMyPropValue = TInnerTupple<typeof myPropTuple>[1];

function getMyProp(val: number) {
    type TKey = TInnerTupple<typeof myPropTuple>[0];

    const mapA2 = new Map(myPropTuple);
    if(!mapA2.has(val as TKey)) throw new RangeError("unexpected value");
    return mapA2.get(val as TKey);
}

// 工具类型(无需内联)
type TTupleType<T extends Iterable<any>> = T extends ReadonlyArray<infer R> ? R :never;
type TInnerTupple<I extends Iterable<any>> = TTupleType<I>;

// 测试用例
console.assert(getMyProp(1) === "dog");
//console.assert(getMyProp(1) === "turle");    // 触发编译错误

const a: TMyPropValue = "cat";
//const b: TMyPropValue = "eagle";    // 触发编译错误

但我希望将这个函数改造成泛型形式,同时保留类型安全,最终能写出这样的代码:

const myPropTuple = [
    [0, "cat"],
    [1, "dog"],
    [2, "bird"]
] as const;

console.assert(getGenericProp(myPropTuple, 1) === "dog");

const yourPropTuple = [
    [0, "fish"],
    [1, "towel"],
    [2, "whale"]
] as const;

console.assert(getGenericProp(yourPropTuple, 0) === "fish");

并且以下代码需要触发编译错误:

console.assert(getGenericProp(myPropTuple, 1) === "turle");    // 触发编译错误

type TYourPropValue = TInnerTupple<typeof yourPropTuple>[1];
const y: TYourPropValue = "dog";    // 触发编译错误

补充说明

@jcalz提出了一个更简洁的替代方案,扩展后如下:

const animalProps = {
    0: "cat",
    1: "dog",
    2: "bird"
} as const;

function getGenericProp2<T extends object>(props: T, val: keyof T): T[keyof T] {
    const found = props[val];
    if(found === undefined) throw new RangeError("unexpected value");
    return found;
}
type TValues = ValueOf<typeof animalProps>;
type TKeys = keyof typeof animalProps;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:18:23