1

The below code is accepted by TypeScript, in strict mode, though I don't want it to be. The function's value argument is legitimately an unknown or an any type: it's allowed to be anything at this stage, as it's being proxied along.

However, due to unknown matching, and the allowed reduction in the number of arguments, the test call is accepted.

interface Mine { x: number }

function handle(
  field: number,
  onChange: (field:Mine, value: unknown) => void,
) {
}

function testCall() {
  handle(123, (value: unknown) => {})
}

Is there any way to reject functions that accept fewer arguments than expected? Or is there a way to reject implicit conversions to unknown?

1 Answer 1

1

A function that takes fewer arguments can be put in place of an function that takes more, and likewise a function that accepts arguments with wider types can be put in place of a function that takes narrower types. (Documentation)

Specifically, in this case, (value: unknown) => void can take 2 parameters, and since value is unknown, it should be able to handle a value of type Mine.

A common example of where this is used is .map. .map((v: unknown) => `${v}`) works, even though map also has an argument for the index, and an argument for the original array.


If it's vitally important that you can't accidentally not include a type, you could instead use a class with properties instead of arguments, and a main method that takes no arguments:

abstract class OnChange {
  private field: Mine;
  private value: unknown;
  public constructor (field: Mine, value: unknown) { this.field = field; this.value = value; }
  public abstract main(): void;
}

This seems like more trouble than it's worth, though, so I'd just use functions with narrowable arguments, as was intended.

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

4 Comments

Thanks for the documentation reference. I guess the trouble I'm having is dealing with "unknown" types that aren't really unknown, and being subject to unintended type widening. Ideally I Want a type that represents a JSON encodeable value, but not any/unknown
In this case I'm not really sure how that applies. If the function being passed in can handle non-json encodable values, why is that a problem? Also, there's no type for all JSON encodable values, though you could type a subset of them.
In my particular example the issue is that the testCall forgot that it was to receive provide a Mine argument, not that it was to be ignored. The value it wants is actually the second argument of the callback. But since the value type is unknown, this error is not detected.
I understand your problem now, but I don't think typescript can solve it since it's not a typing error. Perhaps switch the order of your arguments?

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.