我想创建一个通用方法,将一个预定义的字符串作为第一个参数,将一些数据作为第二个参数。我希望将“数据”描述为带有这些预定义字符串键的接口
type MyKeys = 'lorem' | 'ipsum' | 'dolor';
interface DataParams extends Record<MyKeys, any | undefined> {
lorem: { year: number };
ipsum: { to: string };
}
myCoolGeneric('lorem', {year: 2021}); // ok
myCoolGeneric('ipsum', {year: 2021}); // typescript error
所以我可以为它们指定多组键和不同的可用参数。并且打字稿将检查该方法是否使用正确的参数调用,具体取决于哪个键用作参数
我应该如何声明 myCoolGeneric?有可能吗?或者也许还有其他一些方法可以实现这种行为?
我尝试了以下代码,但它给出了错误,即键被用作类型中的值
const myCoolGeneric = <P extends Record<string, any | undefined>>(key: keyof P, data P[key]) => { ... }
答案 0 :(得分:1)
谢谢@kaya3!
更新
如果你有不同的允许参数组合,你可以产生函数重载。
type MyKeys = 'lorem' | 'ipsum' | 'dolor';
interface DataParams {
lorem: { year: number };
ipsum: { to: string };
}
// credits goes to https://stackoverflow.com/a/50375286
// function intersection produces - function overloads
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Values<T> = T[keyof T]
/**
* Generate all possible combinations of allowed arguments
*/
type AllOverloads = {
[Prop in MyKeys]:
Prop extends keyof DataParams
? (key: Prop, data: DataParams[Prop]) => any
: (key: Prop) => any
}
/**
* Convert all allowed combinations to function overload
*/
type Overloading = UnionToIntersection<Values<AllOverloads>>
const myCoolGeneric: Overloading = <Key extends MyKeys>(
key: Key,
data?: Key extends keyof DataParams ? DataParams[Key] : void
) => null as any
myCoolGeneric('lorem', { year: 2021 }); // ok
myCoolGeneric('ipsum', { to: '2021' }); // typescript error
myCoolGeneric('dolor'); // ok
在 TypeScript 中,您可以像在 JS 中一样使用方括号表示法:DataParams[Key]
使用通用参数更新
type MyKeys = 'lorem' | 'ipsum' | 'dolor';
interface DataParams {
lorem: { year: number };
ipsum: { to: string };
}
// credits goes to https://stackoverflow.com/a/50375286
// function intersection producec - functin overloads
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Values<T> = T[keyof T]
/**
* Generate all possible combinations of allowed arguments
*/
type AllOverloads<Keys extends string, Mappings> = {
[Prop in Keys]:
Prop extends keyof Mappings
? (key: Prop, data: Mappings[Prop]) => any
: (key: Prop) => any
}
/**
* Convert all allowed combinations to function overload
*/
type Overloading<Keys extends string, Mappings> =
UnionToIntersection<Values<AllOverloads<Keys, Mappings>>>
const myCoolGeneric: Overloading<MyKeys, DataParams> = (
key: string,
data?: unknown
) => null as any
myCoolGeneric('lorem', { year: 2021 }); // ok
myCoolGeneric('ipsum', { to: '2021' }); // typescript error
myCoolGeneric('dolor'); // ok
更新 3
type MyKeys = 'lorem' | 'ipsum' | 'dolor';
interface DataParams {
lorem: { year: number };
ipsum: { to: string };
}
// credits goes to https://stackoverflow.com/a/50375286
// function intersection producec - functin overloads
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type IsNever<T> = [T] extends [UnionToIntersection<T>] ? true : false;
type Values<T> = T[keyof T]
/**
* Generate all possible combinations of allowed arguments
*/
type AllOverloads<Mappings, Keys extends string> = {
[Prop in Keys]:
Prop extends keyof Mappings
? (key: Prop, data: Mappings[Prop]) => any
: (key: Prop) => any
}
/**
* Convert all allowed combinations to function overload
*/
type Overloading<Mappings, Keys extends string> =
keyof Mappings extends Keys
? UnionToIntersection<Values<AllOverloads<Mappings, Keys>>>
: never
const myCoolGeneric: Overloading<DataParams, MyKeys> = (
key: string,
data?: unknown
) => null as any
myCoolGeneric('lorem', { year: 2021 }); // ok
myCoolGeneric('ipsum', { to: '2021' }); // typescript error
myCoolGeneric('dolor'); // ok
尝试添加到 DataParams
非存在键。 TS 会抛出错误