1
class Target {
  prop1 = "321";
}

const target = new Target()

class Target2 {
  prop2 = "123";
}

const target2 = new Target2()

type TValue<V extends object> = {
  target: V;
  key: keyof V;
}

class Case<V extends TValue<any>[]> {
  constructor(private values: V) {}
}

const someCase = new Case([
  {
    target: target,
    key: "123"
  },
  {
    target: target2,
    key: "prop2"
  }
])

目标类型已成功推断,但 keyof 未按预期工作。我究竟做错了什么?

我还创建了一个游乐场

4

1 回答 1

1

我之前的回答 与您的用例类似,但由于我使用了一个函数而您正在处理类,所以它有点不同。


type Entity<Obj, Key> = {
  target: Obj,
  key: Key
}

type IsValid<T extends Entity<any, any>[]> =
  /**
   * Infer each element of the array
   */
  T[number] extends infer Elem
  /**
   * Check if every element of the array extends Entity
   */
  ? Elem extends Entity<any, any>
  /**
   * Check if keyof Elem['object'] extends `key` property
   * 1) if [key] property is one of object properties - return true
   * 2) if at least one element does not meet your requirements return false | true,
   * because some element are ok
   */
  ? keyof Elem['target'] extends Elem['key']
  ? true
  : false
  : false
  : false;

// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
  k: infer I
) => void
  ? I
  : never;

// credits https://stackoverflow.com/users/125734/titian-cernicova-dragomir
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;

type Validator<T extends boolean> =
  /**
   * If IsValid returns false | true (boolean) it means Error
   * otherwise - ok
   */
  IsUnion<T> extends true ?
  ['Dear developer, please do smth right']
  /**
   * I'm using empty array here, because 
   * (...flag:[])=>any evaluates to function without arguments
   */
  : []

class Case<
  Value extends { [prop: string]: any },
  Key extends keyof Value,
  Data extends Entity<Value, Key>[],
  > {
  constructor(private values: [...Data], ...flag: [...Validator<IsValid<[...Data]>>]) { }
}


class Target {
  prop1 = "321";
}

const target = new Target()

class Target2 {
  prop2 = "123";
}

const target2 = new Target2()

const result = new Case([{
  target: target, key: 'prop1'
},
{
  target: target2, key: 'prop2'
}]) // ok

const result_ = new Case([{
  target: target, key: 'prop1'
},
{
  target: target2, key: 'prop1' // wrong
}]) // error

您可以替换['Dear developer, please do smth right'][never]

在这里您可以找到有关推断函数参数的更多信息

于 2021-07-22T11:05:18.513 回答