我的代码格式为this playground:
export enum HTTPMethod {
GET = 'GET',
}
export type FetchData<TData> = (
routeOrBody?: string | BodyInit | object,
body?: BodyInit | object,
) => Promise<TData | undefined>
export type AbortFetch = () => void;
export interface FetchCommands<TData> {
get: FetchData<TData>
abort: AbortFetch
}
export interface UseFetchResult<TData>{
data: TData,
request: FetchCommands<TData>
}
export type FetchResult<TKey extends keyof FetchCommands<TData>, TData> = {
data: TData
} & {
[key in TKey]: any
}
const makeHttpVerbMethod = <TData, TMethod extends keyof FetchCommands<TData>>(
httpMethod: HTTPMethod,
) => (incoming: TData): FetchResult<TMethod, TData> => {
const methods: FetchCommands<TData> = {
get: () => Promise.resolve(undefined),
abort: () => undefined
}
const {request}: UseFetchResult<TData> = { data: incoming, request: methods }
const commandKey = httpMethod.toLowerCase() as TMethod
const httpFunc = request[commandKey]
const result: FetchResult<TMethod, TData> = {
data: incoming,
[commandKey]: httpFunc,
}
return result
}
基本上,我想向makeHttpVerbMethod
函数返回的内容添加一个密钥,但是我不确定是否有可能,我正在使用通用类型参数来尝试限制可以调用的密钥:
const makeHttpVerbMethod = <TData, TMethod extends keyof FetchCommands<TData>>(
httpMethod: HTTPMethod,
) => (incoming: TData): FetchResult<TMethod, TData> => {
我想为makeHttpVerbMethod
的返回类型添加动态键
但是我认为tsc变得很困惑,因为尝试分配给result
时收到此错误消息。
键入'{[x:字符串]:TData | FetchCommands [TMethod];数据:TData; }”不可分配给“ FetchResult”类型。 类型'{[x:string]:TData | FetchCommands [TMethod];数据:TData; }'不可分配为类型'{[TMethod中的键]:任何; }'。
我不知道{ [x: string]
的来源
如果我将函数更改为使用显式'get'
文字,那么这一切都可以工作
const makeHttpVerbMethod = <TData, TMethod extends keyof FetchCommands<TData>>(
httpMethod: HTTPMethod,
) => (incoming: TData): FetchResult<'get', TData> => {
const methods: FetchCommands<TData> = {
get: () => Promise.resolve(undefined),
abort: () => undefined
}
const {request}: UseFetchResult<TData> = { data: incoming, request: methods }
const commandKey = 'get'
const httpFunc = request[commandKey]
const result: FetchResult<'get', TData> = {
data: incoming,
[commandKey]: httpFunc,
}
return result
}
是否可以使用参数化类型TMethod来实现此目的?
答案 0 :(得分:0)
这里的问题之一似乎是known bug,据此,具有{[commandKey]: httpFunc}
之类的已计算属性的对象将其键扩展为string index,这就是为什么编译器抱怨{{1 }}与string
不匹配。当您仅用TMethod
替换它时,它就可以工作,因为单个字符串文字类型的计算键不会扩展为"get"
。现在没有解决办法。只有解决方法。
我在这里建议的解决方法是使用一个辅助函数,该函数需要一个string
类型的键和一个K
类型的值,并返回一个V
类型的对象(表示键是Record<K, V>
,值是K
):
V
仅当已知function keyValue<K extends keyof any, V>(key: K, value: V) {
const ret = {} as Record<K, V>;
ret[key] = value;
return ret;
}
仅是单个键类型而不是联合时,这才是类型安全的:
K
(可以解决此问题,以便正确键入const goodUseOfKeyValue = keyValue("hey", "you"); // {hey: "you"}
const notGoodUseOfKeyValue = keyValue(Math.random() < 0.5 ? "oh" : "no", 1);
// supposedly type {oh: number, no: number},
// but of course it's really {oh: number} | {no: number}
,但是在这里我们不需要它,因为您希望notGoodUseOfKeyValue
是单个字符串文字)。
现在,我们将使用TMethod
和Object.assign()
来代替
const result: FetchResult<TMethod, TData> = Object.assign(
{ data: incoming },
keyValue(httpMethod, request[httpMethod])
); // okay, no error
好的,希望能有所帮助;祝你好运!