The TypeScript `unknown` type restricts the use of non-unknown types in function parameters

Why is there an error in this code?

const x: unknown[] = ['x', 32, true]; // OK
const y: (...args: unknown[]) => unknown = (xx: number) => {}; // ERROR

// Type '(xx: number) => void' is not assignable to type '(...args: unknown[]) => unknown'.
// Types of parameters 'xx' and 'args' are incompatible.
// Type 'unknown' is not assignable to type 'number'. ts(2322)

My objective here is to ensure that y is a valid executable function without using the any type. I am looking to enhance my understanding of how unknown functions in such scenarios.

Answer №1

When it comes to function types, they exhibit contravariant behavior in their parameter types. To understand this concept better, refer to the article on Difference between Variance, Covariance, Contravariance and Bivariance in TypeScript. In simple terms, contravariance means that if a type T can be assigned to type U, then the function (...u: U) => void is assignable to (...t: T) => void, and not the other way around. This direction of assignability is crucial for maintaining type safety. Think of data flow: I can give you an apple if you want fruit, but I cannot hand you something that eats only apples when you need something to consume all your fruit.


The function type (xx: number) => void is effectively equivalent to (...args: [number]) => void, and it cannot be directly assigned to (...args: unknown[]) => void. Even though [number] can be assigned to

unknown[]</code, our concern here is not about that specific direction. Hence, trying such an assignment would lead to unsafe behavior. For instance:</p>
<pre><code>const y: (...args: unknown[]) => unknown =
    (xx: number) => xx.toFixed(); // Should this actually work?

If the above code was allowed, calling y() with any arguments would compile successfully without errors, but result in a runtime error:

y("x", 32, true); // No compiler error
// 💥 Error! xx.toFixed is not a function

By widening the input argument list to unknown[], we unintentionally make the function type too narrow since most functions do not cater to every possible argument combination.


If you want a type that accepts any function at all, you'd have to limit the input argument list to a type like never which does not accept any inputs:

type SomeFunction = (...args: never) => unknown;
const y: SomeFunction = (xx: number) => xx.toFixed(); // This works fine
// const y: SomeFunction

This approach works because SomeFunction becomes practically uncallable. If someone asks for a function they won't call, any function will suffice. Conversely, if a function's expected arguments are unknown, it should not be called unknowingly.

While this method accomplishes the task, it doesn't offer much functionality beyond the initial assignment:

y(123); // Results in an error as argument types are no longer known

In your use case, where these "uncallable" functions might be passed to environments unaware of TypeScript's type rules, this limitation may not pose a problem.


For others interested in verifying assignments without broadening them, using the satisfies operator is a valuable technique. Instead of explicitly annotating y as

SomeFunction</code, consider checking it against that type via <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator" rel="noreferrer">the satisfies operator</a>:</p>
<pre><code>const y = ((xx: number) => xx.toFixed()) satisfies SomeFunction;
// const y: (xx: number) => string

This method compiles successfully (but fails with incorrect usage), confirming that y remains as (xx: number) => string. Therefore, you can continue calling it as usual:

y(123); // Works fine

Playground link to code

Answer №2

Why is this not functioning properly?

This snippet highlights an error:

let x: unknown[] = ['x', 32, true]; // No issues here
let y: (...args: unknown[]) => unknown = (xx: number) => {}; // However, there's a problem with this line

Similar to why the following code block encounters an error:

let x: unknown = 123; // Works fine
let y: number = x; // ERROR: unable to assign unknown to number 

To put it simply: You must verify the runtime value of unknown before assigning it to any other data type.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to retrieve information from a local JSON file and store it in the state of

I am currently working on a project to develop a movies/series search app using Next.js and React based class components. I have successfully imported JSON content and displayed it using the map function as shown below: <div> {Appletv.shows.map(( ...

PersistJS callback function is malfunctioning

I stumbled upon a great library for managing client storage. You can find the latest version here: https://github.com/jeremydurham/persist-js However, I encountered an issue with the callback function. var result = store.get('saved_data', func ...

Troubden array filtration in Angular is malfunctioning

I recently developed an angular "filter component" intended to filter an array and display its contents. The keyword used to filter the array, value, is obtained from another component through a service. While the HTML displays both the value and the entir ...

Cross-Origin Resource Sharing Problem - Angular version 8 with NodeJS and ExpressJS

I've attempted various solutions from different sources and have a feeling that I may be overlooking something minor here. In my setup, I have an AngularJS 8 application running on Node 10 with ExpressJS. The specific issue I'm encountering rela ...

Is it possible that the images are unable to load on the page

The frontend code successfully retrieves the image links sent by the backend but encounters issues displaying them. Despite confirming that the imgUrl data is successfully fetched without any hotlink protection problems, the images are still not appearing ...

Adjust the height of a div vertically in Angular 2+

Recently, I started using angular2 and I've been attempting to create a vertically resizable div without success. I have experimented with a directive for this purpose. Below is the code for my directive: import { Directive, HostListener, ElementRef ...

Can you explain the significance of the 'X-Bandwidth-Est 3' error message that states, "Refused to get unsafe header"?

I'm currently facing an issue with all the websites I am working on where I keep encountering the following error: Refused to get unsafe header "X-Bandwidth-Est 3" in base.js. This error seems to be related to a YouTube file named base.js, but after ...

Tips for showing and modifying value in SelectField component in React Native

At the moment, I have two select fields for Language and Currency. Both of these fields are populated dynamically with values, but now I need to update the selected value upon changing it and pressing a button that triggers an onClick function to update th ...

JQuery Keyup event is not functioning as expected

For my blog navigation, I have set up an event where pressing the 'J' key takes me to the previous post and the 'K' key takes me to the next post. However, I am facing an issue where the event works initially but stops working after the ...

Exploring the concept of unprojection in three.js

Check out this jsfiddle example of what I am trying to achieve - seeing a 3D object drawn exactly behind the cursor as it moves across the screen. http://jsfiddle.net/ksRyQ/3551/ unp = p.unprojectVector(new THREE.Vector3( mx - (window.innerWidth/2), (wi ...

Link the <select> element with ng-options and ng-model, ensuring that the model contains a composite key

I am facing a challenge with my Angular service that retrieves a list of objects with a composite key comprising two parts. I am struggling to write the bindings in a way that properly re-binds existing data. Below is my current attempt: angular.module( ...

Interactive radio button that only registers the most recent click

Homepage.jsx const Homepage = () => { const [categories, setCategories] = useState([]) const [products, setProducts] = useState([]) const [selected, setSelected] = useState("all") const getAllCategories = async() => { try{ ...

I have noticed that my unit test case does not include coverage for the if statement

Here is the function I have in my TypeScript file: routeToIndividualPortal(sessionToken: string) { let redirectUrl = this.relayState; console.log("Pre-source-check Indivual URL : " + redirectUrl); let url = ""; if(redirectUrl.includes(this. ...

Hide elements forever once the form is submitted

I'm seeking help to figure out how to make certain elements disappear after a form submission on my website's dashboard page. Specifically, I need to hide three elements once the user has submitted a form. Elements that need to be hidden: .vc_t ...

Learn how to dynamically disable a button based on the input state matching an email pattern!

I'm facing an issue with my login form that has 2 input fields and a login button. One of the input fields requires a valid email pattern. If any of the input fields are left empty, the login button becomes disabled. However, when an incorrect email p ...

Learn how to toggle the display of a div using jQuery, just like the functionality on the popular website

Visit Mashable here Below is the script I am currently using: $(document).ready(function(){ $(".show_hide5").mouseover(function(){ $('.selected').removeClass('selected'); $(this).next().fadeIn("slow").addClass(&apo ...

Using JavaScript within HTML documents

Need help with inserting JavaScript code from Google: <script type='text/javascript'> googletag.cmd.push(function() { googletag.display('div-gpt-ad-1362706866260-0'); }); </script> into existing JavaScript / HTML code: va ...

Having trouble reloading a seekbar (input range) in Angular 7 with a function?

I am currently in the process of developing a music player using Angular 7, and below is the HTML code for my component: <div class="track-controller"> <small>{{musicPlayerService.getCurrentTime()}}</small> <div class="progress- ...

"Encountered an undefined error with the title property of this.state.project in the Wordpress API

I'm currently working on a project that involves a Backend Wordpress and a front-end React setup. However, I've encountered an issue when attempting to retrieve the title.rendered from the JSON Data. This error is displayed: TypeError: this.sta ...

What factors might cause varying WebGL extension availability?

When I analyze my code, I am checking for available WebGL extensions. console.log(GL.getSupportedExtensions()); This results in an array containing 9 extensions. https://i.sstatic.net/5sTcX.png However, upon inspecting my extensions on a platform like ...