Consider the following class and types:
type keyCollection = {
[key: string]: {
request: any,
response: any
}
}
class myTest<TData extends keyCollection = any> {
testFunction<
TInput extends keyof TData,
TObject = TData extends keyCollection ? TData[TInput]['request'] : any>(input: TInput, data: TObject) {}
}
My goal is, that if this class is instantiated without any generic parameter, the testFunction
should accept any string
as it's first parameter, and anything as it's second parameter. Yet, when a generic is passed to the class, it should constrain the values of the testFunction
.
Here are some test cases:
let a: myTest = new myTest();
a.testFunction('test', {}); // works as expected, no generic parameter for the class, thus accepts string as first parameter, and any as second
type testGenericKeyCollection = {
a: {
'request': string,
'response': any
},
b: {
'request': string,
'response': any
}
}
let b: myTest<testGenericKeyCollection> = new myTest();
b.testFunction("c", 25); // correctly errors out, as "c" as not a property of
b.testFunction("a", 25); // why no error here? 25 is type number not type string - also, why no type helping here?
As you can see in the comments, the instantiation without generic seems to work in the first test case - the function accepts any string as it's first parameter, and anything as it's second parameter.
As for the second case, it still is ok, when the class is instantiated with a generic type provided, testFunction
does not accept "c" as it's first parameter anymore, because it is not a property of the provided generic.
Yet, for the third test-case, while it correctly identifies the key from the input, it allows any type as the second parameter, and I can't figure out why. The third test-case should only accept a string
type as it's second parameter.
Why is this not working the way I am expecting it to work?
Fiddle here
CodePudding user response:
You are using a default type (TObject = ...
) instead of a type constraint:
class myTest<TData extends keyCollection = any> {
testFunction<
TInput extends keyof TData,
TObject extends TData extends keyCollection ? TData[TInput]['request'] : any>(input: TInput, data: TObject) {}
}