我之前的回答 与您的用例类似,但由于我使用了一个函数而您正在处理类,所以它有点不同。
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]
在这里您可以找到有关推断函数参数的更多信息