打字稿:如何将字符串类型映射到具有许多不同子类型的泛型
Typescript: How to map string type to generic with many different subtypes
我正在尝试在本地存储之上创建一个类型化接口,我可以仅使用字符串键以类型化方式从本地存储set/get。我想要将字符串类型映射到泛型,这样我就可以自定义 serialization/deserialization.
我 运行 遇到的问题是,当我使用映射对象从字符串类型转换为通用对象时,Typescript 似乎无法正确推断类型。如果有人对解决此问题的最佳方法有一些好的建议,那就太棒了! ❤️
下面有一个例子可以更好地解释我的情况:
type LocalStorageKey = "bool_test" | "num_test";
type LocalStorageKeyInfo<T> = {
key: LocalStorageKey;
getDefault(): T;
serialize(val: T): string;
deserialize(lsVal: string | null, defaultVal: T): T;
};
const BooleanSerializer = (val: boolean) => String(val);
const BooleanDeserializer = (lsVal: string | null, defaultVal: boolean) => {
if (lsVal === null) {
return defaultVal;
} else {
return lsVal === "true";
}
};
const NumberSerializer = (val: number) => String(val);
const NumberDeserializer = (lsVal: string | null, defaultVal: number) => {
if (lsVal === null) {
return defaultVal;
} else {
return Number(lsVal);
}
};
export const BoolTestKeyInfo: LocalStorageKeyInfo<boolean> = {
key: "bool_test",
getDefault: () => false,
serialize: BooleanSerializer,
deserialize: BooleanDeserializer,
};
export const NumTestKeyInfo: LocalStorageKeyInfo<number> = {
key: "num_test",
getDefault: () => 0,
serialize: NumberSerializer,
deserialize: NumberDeserializer,
};
const keyInfoMapping = {
bool_test: BoolTestKeyInfo,
num_test: NumTestKeyInfo,
};
export function getKeyVal(key: LocalStorageKey) {
const keyInfo = keyInfoMapping[key];
try {
return keyInfo.deserialize(
window.localStorage.getItem(keyInfo.key),
// This line is the issue because deserialize's second arg is infered as never
keyInfo.getDefault()
);
} catch (e) {
return keyInfo.getDefault();
}
}
// I want x to be a boolean here
const x = getKeyVal("bool_test");
您可以通过向函数添加泛型类型参数以捕获传入的 key
的实际类型,将 x
变为 boolean
。但是您仍然会在实现中需要一些类型断言,因为 ts 不能很好地遵循变量之间的相关性。
export function getKeyVal<K extends LocalStorageKey>(key: K) :ReturnType<typeof keyInfoMapping[K]['getDefault']>
export function getKeyVal(key: LocalStorageKey) {
const keyInfo = keyInfoMapping[key];
try {
return keyInfo.deserialize(
window.localStorage.getItem(keyInfo.key),
// This line is the issue because deserialize's second arg is infered as never
keyInfo.getDefault() as never
);
} catch (e) {
return keyInfo.getDefault();
}
}
我正在尝试在本地存储之上创建一个类型化接口,我可以仅使用字符串键以类型化方式从本地存储set/get。我想要将字符串类型映射到泛型,这样我就可以自定义 serialization/deserialization.
我 运行 遇到的问题是,当我使用映射对象从字符串类型转换为通用对象时,Typescript 似乎无法正确推断类型。如果有人对解决此问题的最佳方法有一些好的建议,那就太棒了! ❤️
下面有一个例子可以更好地解释我的情况:
type LocalStorageKey = "bool_test" | "num_test";
type LocalStorageKeyInfo<T> = {
key: LocalStorageKey;
getDefault(): T;
serialize(val: T): string;
deserialize(lsVal: string | null, defaultVal: T): T;
};
const BooleanSerializer = (val: boolean) => String(val);
const BooleanDeserializer = (lsVal: string | null, defaultVal: boolean) => {
if (lsVal === null) {
return defaultVal;
} else {
return lsVal === "true";
}
};
const NumberSerializer = (val: number) => String(val);
const NumberDeserializer = (lsVal: string | null, defaultVal: number) => {
if (lsVal === null) {
return defaultVal;
} else {
return Number(lsVal);
}
};
export const BoolTestKeyInfo: LocalStorageKeyInfo<boolean> = {
key: "bool_test",
getDefault: () => false,
serialize: BooleanSerializer,
deserialize: BooleanDeserializer,
};
export const NumTestKeyInfo: LocalStorageKeyInfo<number> = {
key: "num_test",
getDefault: () => 0,
serialize: NumberSerializer,
deserialize: NumberDeserializer,
};
const keyInfoMapping = {
bool_test: BoolTestKeyInfo,
num_test: NumTestKeyInfo,
};
export function getKeyVal(key: LocalStorageKey) {
const keyInfo = keyInfoMapping[key];
try {
return keyInfo.deserialize(
window.localStorage.getItem(keyInfo.key),
// This line is the issue because deserialize's second arg is infered as never
keyInfo.getDefault()
);
} catch (e) {
return keyInfo.getDefault();
}
}
// I want x to be a boolean here
const x = getKeyVal("bool_test");
您可以通过向函数添加泛型类型参数以捕获传入的 key
的实际类型,将 x
变为 boolean
。但是您仍然会在实现中需要一些类型断言,因为 ts 不能很好地遵循变量之间的相关性。
export function getKeyVal<K extends LocalStorageKey>(key: K) :ReturnType<typeof keyInfoMapping[K]['getDefault']>
export function getKeyVal(key: LocalStorageKey) {
const keyInfo = keyInfoMapping[key];
try {
return keyInfo.deserialize(
window.localStorage.getItem(keyInfo.key),
// This line is the issue because deserialize's second arg is infered as never
keyInfo.getDefault() as never
);
} catch (e) {
return keyInfo.getDefault();
}
}