我正在try 编写一个类型安全的映射对象.我只想定义一次键/值对.
我在以下方面取得了成功:
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);
}
// helper library (not to be inlined)
type TTupleType<T extends Iterable<any>> = T extends ReadonlyArray<infer R> ? R :never;
type TInnerTupple<I extends Iterable<any>> = TTupleType<I>;
// Tests
console.assert(getMyProp(1) === "dog");
//console.assert(getMyProp(1) === "turle"); // throws compiler error
const a: TMyPropValue = "cat";
//const b: TMyPropValue = "eagle"; // throws compiler error
但我希望使该函数成为泛型,并仍然维护类型安全:
我们的目标是能够写作
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"); // throws compiler error
type TYourPropValue = TInnerTupple<typeof yourPropTuple>[1];
const y: TYourPropValue = "dog"; // throws compiler error
addendum个
@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;