Typescript泛型基于参数返回类型



如何基于参数执行动态typescript返回类型尚未定义。请帮忙。

还添加了一个Typescript Playground Snippet以供参考

我已经想出了这个办法,但没有像预期的那样奏效。

V extends keyof T ? ToObject<T> : ToObject<T[keyof T]>

代码:

export interface ToObject<T> {
[k: string]: T;
}
export const toObject = <T, V = (keyof T)>(
list: T[],
key: keyof T,
valueKey?: V
): V extends keyof T ? ToObject<T> : ToObject<T[keyof T]> => valueKey === undefined
? list.reduce((all, cur) => ({
...all,
[cur[key] as unknown as string]: cur
}), {} as ToObject<T>)
: list.reduce((all, cur) => ({
...all,
[cur[key] as unknown as string]: cur[valueKey as unknown as keyof T]
}), {} as ToObject<T[keyof T]>);

用法:

interface Data{
a: string;
b: string;
c: string;
}
const list: Data[] = [
{a:'a', b: 'b', c: 'c'},
{a:'1', b: '2', c: '3'}
];
// use 1
toObject<Data>(list, 'a');
// response
{
{'a': {a:'a', b: 'b', c:'c'}},
{'1': {a:'1', b:'2', c: '2'}},
}
// Use 2
toObject<Data>(list, 'a', 'b');
//response
{ {'a': 'b'}, {'1': '2'} }

问题:

// use 1 ERROR -> Cant do this
const dataMap: ToObject<Data> = toObject<Data>(list, 'a');
// Type 'ToObject<Data> | ToObject<string>' is not assignable to type 'ToObject<Data>'.
// Type 'ToObject<string>' is not assignable to type 'ToObject<Data>'.
// Type 'string' is not assignable to type 'Data'.(2322)
// Use 2 ERROR -> Cant do this
const dataKeyMap: ToObject<string> = toObject<Data>(list, 'a', 'b');
// Type 'ToObject<Data> | ToObject<string>' is not assignable to type 'ToObject<string>'.
// Type 'ToObject<Data>' is not assignable to type 'ToObject<string>'.
// Type 'Data' is not assignable to type 'string'.(2322)

正如所写的,TS没有足够的信息来区分toObject的两种返回类型。

如果我们添加函数重载,我们可以将返回类型绑定到函数签名。如果CCD_ 2通过,toObject返回ToObject<T[keyof T]>,否则函数返回ToObject<T>

修订后的游乐场

export function toObject <T, V = (keyof T)>(list: T[], key: keyof T): ToObject<T>
export function toObject <T, V = (keyof T)>(list: T[], key: keyof T, valueKey: V): ToObject<T[keyof T]>
export function toObject <T, V = (keyof T)>(list: T[], key: keyof T, valueKey?: V): ToObject<T> | ToObject<T[keyof T]> {
return valueKey === undefined
? list.reduce((all, cur) => ({
...all,
[cur[key] as unknown as string]: cur
}), {} as ToObject<T>)
: list.reduce((all, cur) => ({
...all,
[cur[key] as unknown as string]: cur[valueKey as unknown as keyof T]
}), {} as ToObject<T[keyof T]>);
}  

除了让TS编译器高兴之外,重载还通知用户应该如何调用函数。

最新更新