TypeScript泛型和函数参数

subvertallchris

我正在努力改善Rosie的清晰度,Rosie目前非常依赖any并且在安全性方面没有提供太多帮助。我目前有些困惑,可以使用一些建议。

我正在尝试写一个表示以下内容的签名:

// this is invalid, but something like this is the goal
interface IFactory<T = any> {
  attr<K extends keyof T, D extends keyof T>(name: K, dependencies: D[], generatorFunction: (value1?: D[0], value2?: D[1], value3?: D[2]), value4?: D[3] => T[K]): IFactory<T>;
}

第二个参数中给出了一个键数组。这些值以提供的相同顺序作为参数传递给函数。我想避免不必要的类型转换,因此我们应该得到以下信息:

Factory.define<Person>('Person').attr('fullName', ['firstName', 'lastName', 'age'], (firstName, lastName, age) => {
   // it knows that firstName is a string, lastName is a string, age is a number

  if (age > 10) { 
    // this will error
    return age; 
  }

  return `${firstName} ${lastName};     
});

我能得到的最接近的是:

attr<K extends keyof T, D extends keyof T>(name: K, dependencies: D[], generatorFunction: (value1: T[D], value2: T[D], value3: T[D], value4: T[D]) => T[K]): IFactory<T>;

这将最多键入4个依赖值,但是调用它需要显式强制转换,并且不会以正确的顺序设置类型:

// it knows that each of the three arguments are string | number
existingDefinition.attr('fullName', ['firstName', 'lastName', 'age'], (firstName: string, lastName: string, age: number) => `${firstName} ${lastName}`);

这使我可以在不破坏依赖关系的情况下更改其顺序,这是不好的。如果我提供的参数多于依赖值,它也不会出错。我想找到一种表达方式“类型generatorFunction为”中的每个元素都有一个参数”。dependenciesT[DependencyName]

我希望这是有道理的。感谢任何人都能提供的帮助。

马达拉的幽灵

您将需要对每个Arity(签名)进行重载。例如,看一下Reselect如何做事

/* one selector */
export function createSelector<S, R1, T>(
  selector: Selector<S, R1>,
  combiner: (res: R1) => T,
): OutputSelector<S, T, (res: R1) => T>;
export function createSelector<S, P, R1, T>(
  selector: ParametricSelector<S, P, R1>,
  combiner: (res: R1) => T,
): OutputParametricSelector<S, P, T, (res: R1) => T>;

/* two selectors */
export function createSelector<S, R1, R2, T>(
  selector1: Selector<S, R1>,
  selector2: Selector<S, R2>,
  combiner: (res1: R1, res2: R2) => T,
): OutputSelector<S, T, (res1: R1, res2: R2) => T>;
export function createSelector<S, P, R1, R2, T>(
  selector1: ParametricSelector<S, P, R1>,
  selector2: ParametricSelector<S, P, R2>,
  combiner: (res1: R1, res2: R2) => T,
): OutputParametricSelector<S, P, T, (res1: R1, res2: R2) => T>;

/* three selectors */
export function createSelector<S, R1, R2, R3, T>(
  selector1: Selector<S, R1>,
  selector2: Selector<S, R2>,
  selector3: Selector<S, R3>,
  combiner: (res1: R1, res2: R2, res3: R3) => T,
): OutputSelector<S, T, (res1: R1, res2: R2, res3: R3) => T>;
export function createSelector<S, P, R1, R2, R3, T>(
  selector1: ParametricSelector<S, P, R1>,
  selector2: ParametricSelector<S, P, R2>,
  selector3: ParametricSelector<S, P, R3>,
  combiner: (res1: R1, res2: R2, res3: R3) => T,
): OutputParametricSelector<S, P, T, (res1: R1, res2: R2, res3: R3) => T>;

// etc...

对每个数量的参数进行重载,直到有一个合理的数量(您期望有多少个?4?8?),然后超过该数量才使用非约束泛型,然后让用户输入。如果您有8个以上的参数,则可能会伤害您输入。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章