Reputation: 517
I would like to obtain the following behaviour without using a T as any:
interface Test<T> {
sameField: string;
test: T
testFunction: (e: T) => void
}
const array: Array<Test</*something something*/_>> = [
{
sameField: "foo",
test: 1,
testFunction: (e) => {
e.toExponential(2) // Should be Valid
e.indexOf('e') // Should be Invalid
}
},
{
sameField: "bar",
test: "baz",
testFunction: (e) => {
e.indexOf('e') // Is Valid
e.toExponential(2) // Should be Invalid
}
}
]
The idea behind it is just a way of telling Typescript "let the array elements handle their typing themselves". Is it only possible to do in Typescript ?
Upvotes: 0
Views: 84
Reputation: 33041
TS is unable to infer e
argument in such kind of data structure on his own.
You have several options here.
First
Define your test
property upfront:
type Main = {
foo: string;
bar: number;
};
type Validator<T extends keyof Main> = {
test: T;
isValid: (value: Main[T]) => boolean;
};
type Values<T> = T[keyof T]
type MainValidationRule = Values<{
[P in keyof Main]: {
test: P;
isValid: (value: Main[P]) => boolean;
}
}>
const validators: Array<MainValidationRule> = [
{ test: 'foo', isValid: (value/* infered to stirng */) => true },
{ test: 'bar', isValid: (value/* infered to number */) => true }
]
Second
interface Test<T> {
field: string;
test: T
fn: (e: T) => void
}
const builder = <Test, Field>(test: Test, field: Field, fn: (e: Test) => any) => ({
field,
test,
fn
})
const array = [builder(2, 'hello', (e/**infered to number */) => 42)]
Here, in my blog, you can find more information about using and typing callbacks
There is one more way to do it:
interface Foo {
sameField: "foo",
test: 1,
testFunction(e: this['test']): void
}
const x: Foo = {
sameField: "foo",
test: 1,
testFunction(e) {
e.toExponential(2) // ok
e.indexOf('e') // error
}
}
But as you might have noticed, you should declare your sameField
and test
upfront
There are more options to do it, but I believe it will be an overhead
Upvotes: 1