1

I have the following types:

export type SchemaEntry<A extends object, B> =
  | Validator<B>
  | ((obj: A) => Validator<B>);
export type Schema<A extends object> = { [k in keyof A]: SchemaEntry<A, A[k]> };

And a function that uses them:

function foo<A extends object>(f: Schema<A>): A {
  return undefined as any;
}

My issue is that when I call the function:

const a = foo({
  b: new Validator<number>(),
  c: (o) => new Validator<number>()
});

o's type will in this case be any rather than my expected {b: number, c: number}. a does however receive the correct type, {b: number, c: number}.

Is there a way that I can help typescript infer the type on my anonymous function?

2
  • 1
    Here's an answer to a similar question which says why it doesn't work: the function parameter inference can't happen if the type it needs to infer is generic or depends on a generic parameter. Commented Apr 9, 2018 at 18:56
  • Thank you. Wish I could solve it the same way! :( Commented Apr 9, 2018 at 21:38

1 Answer 1

1

The type inference flows from the parameter value to the function rather than the other way around. foo sees that the parameter you are passing in is applicable to the parameter constraints and thus allows it, but it's not going to retroactively type the untyped object for you.

Consider if you had written:

const input = {
  b: new Validator<number>(),
  c: (o) => new Validator<number>()
};

const a = foo(input);

After foo is called, you would not expect the type of input to be changed.

If you want to help typescript understand the type of o you will need to help it understand the strict type of the input object you are creating by typing it directly.

Doing so would also enable you to not explicitly type the Validator generics of <number> since that should also be inferred from the overall type.

I'd recommend trying to write the code I have written above, but give it a specific type const input: <Your_Type_Here> = {...

Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, that does make sense. I did hope that it could be done in a way though.. :p I mean. I can write the type as you say. const input: { b: Validator<number>, c: (o: { b: number, c:number }) => Validator<number> }. The only reason I explicitly typed Validator was for this snippet. I don't have to in my actual implementation, as it is function calls that have a return type. Having to type input or o is what I wanted to avoid. As soon as I try to type o, it will tell me that is has to be assignable to {b: number, c:number} though?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.