Uncover the mystery behind the return value of a generic function in TypeScript

I can't seem to wrap my head around why TypeScript is behaving in the way described below.

Snippet

01| const dictionary: { [key: string]: unknown} = {}
02|
03| function set<T>(key: string, value: T): void {
04|    dictionary[key] = value;
05| }
06|
07| function get<T = unknown>(key: string): T {
08|    return dictionary[key] as T;
09| }
10|
11| set('foo', 'bar');
12|
13| const a: string = get('foo');
14|
15| const _b = get('foo');
16| const b: string = _b;

Playground Link

Behavior

TS throws an error on Line 16 but not Line 13.

Expectation

Considering that the generic type T of the get function defaults to unknown, I expected both Line 13 and Line 16 to trigger TS errors since unknown shouldn't be able to be assigned to a variable of type string. Surprisingly, it doesn't flag Line 13, and when I hover over the get function on Line 13, it shows the return value as a string instead of unknown.

I've spent hours trying to make sense of this behavior. Any assistance would be greatly appreciated.

Furthermore, as a follow up question, what modifications should I implement to prompt TypeScript to raise errors on both lines?

EDIT

Apologies for any confusion. I actually INTEND for TypeScript to throw errors on both Line 13 & Line 16, pushing me to specify the generic type string. In other words, I want it to require me to use get<string>('foo')

Answer №1

the unknown type cannot be assigned to any other type. If you explicitly declare that a string will be returned here:

const a: string = get('foo');

typescript will assume that the variable a should be of type string. However, in the next line, the output of your get function will be the default value for the generic T that you are providing.

const _b = get('foo');

and since the unknown type can only be itself and cannot be assigned to any other type, an error occurs.

But here is the solution to make it work:

 const _b = get<string>('foo');

by specifying the expected output as a string, the variable assignment in the following line will not throw an error:

const b: string = _b; // no error here

Answer №2

The type unknown can only be assigned to itself (potentially any, but I haven't verified this). But, if you use any as the default type, your issue will be resolved:

01| const data: { [key: string]: any } = {}
02|
03| function assign<T>(key: string, value: T): void {
04|    data[key] = value;
05| }
06|
07| function retrieve<T = any>(key: string): T {
08|    return data[key] as T;
09| }
10|
11| assign('foo', 'bar');
12|
13| const x: string = retrieve('foo');
14|
15| const _y = retrieve('foo');
16| const y: string = _y;

In my opinion, using any is more appropriate in such cases.

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

The assignment of type 'string' to type 'UploadFileStatus | undefined' is not permissible

import React, { useState } from 'react'; import { Upload } from 'antd'; import ImgCrop from 'antd-img-crop'; interface uploadProps{ fileList:string; } const ImageUploader:React.FC <uploadProps> ...

The name 'Diagnostics' cannot be located

I've downloaded the Typescript repository and am currently reviewing the code. However, I keep encountering this recurring error message: Cannot find name 'Diagnostics' This error pops up on lines that are similar to this: Diagnostics._ ...

Leverage Ramda's clone function within a pipeline in a manner that ensures type safety

My goal is to utilize Ramda for cloning and updating objects in a type-safe manner, drawing inspiration from this approach. However, I am facing challenges implementing it in a type-safe way. Updating a nested object seems to work perfectly fine in a type ...

Creating Dynamic Ionic Slides with Additional Slides Inserted Before and After

Hello, I am currently using ngFor to generate a set of 3 slides with the intention of starting in the middle so that I can smoothly slide left or right from the beginning. When I slide to the right, I can easily detect when the end is reached and add anot ...

Utilizing TypeScript in a browser with a .NetCore WebApplication

After going through numerous articles, I have not been successful in finding a solution. My challenge lies with a .net core WebApplication that utilizes typescript code instead of javascript. Here are the specific requirements: I need to be able to debu ...

Tips for integrating JavaScript libraries with TypeScript

I'm looking to add the 'react-keydown' module to my project, but I'm having trouble finding typings for it. Can someone guide me on how to integrate this module into my TypeScript project? ...

I am facing the dilemma of having an identical button appearing in two separate locations. How can I determine which button has been clicked?

I am currently using ng2-smart-table and have implemented a custom filter with the same button in both filters. However, I am unsure of how to determine which button is being clicked. https://i.stack.imgur.com/b1Uca.png Below is the component code for th ...

Utilize Firebase for Playwright to efficiently implement 'State Reuse' and 'Authentication Reuse'

In my testing environment, I want to eliminate the need for repeated login actions in each test run. My approach involves implementing 'Re-use state' and 'Re-use Authentication', but I've encountered a challenge with Firebase using ...

Error Message: Angular 5 - Unable to bind to 'ngModel' as it is not recognized as a valid property of 'input'

I am currently working on an Angular 5 online tutorial using Visual Studio Code and have the following versions: Angular CLI: 7.0.6 Node: 10.7.0 Angular: 7.0.4, Despite not encountering any errors in Visual Studio Code, I am receiving an error in ...

The promise chain from the ngbModal.open function is being bypassed

I'm currently working on implementing data editing within a component. My task involves checking if any of the data fields have been altered, and if so, prompting a confirmation pop-up to appear. If the user confirms the change, the data will then be ...

When working with TypeScript, it's important to note that an implicit 'any' type may occur when trying to use an expression of type 'string' to index a specific type

Currently, I'm attempting to transfer a custom hook used in Vue for handling i18n from JavaScript to TypeScript. However, I am encountering a persistent error message: An element is implicitly assigned the type 'any' due to an expression o ...

Exiting a void method in JavaScript/Typescript using the return or break statement

I find myself dealing with a complex method in Typescript that contains multiple if else if else constructs. It's a void method, and I'm wondering how I can exit the method based on a specific if condition without having to execute the remaining ...

Decide on the chosen option within the select tag

Is there a way to pre-select an option in a combobox and have the ability to change the selection using TypeScript? I only have two options: "yes" or "no", and I would like to determine which one is selected by default. EDIT : This combobox is for allow ...

How can I implement a master-detail view in Angular 2?

Update: I finally figured it out. After moving all the html from index.html to app.component.ts, everything started working perfectly. The method described below is the correct one. I've been facing an issue where I have a ParentComponent that retrie ...

The error message "Property 'zip' is not available on the 'Observable' type in Angular 6" indicates that the zip property is not recognized by

I've been working with Angular 6 and I've also looked into using pipes, but I couldn't find the correct syntax for writing a zip function and importing it properly. Error: Property 'zip' does not exist on type 'typeof Observ ...

Using TypeScript to create a generic type that wraps around HTMLElements

I attempted to execute this action, however the assignment to this.element is not working and I am unsure why. class Elem<T> { public element : T; constructor(typeElement:string){ this.element = document.createElement(typeElement); ...

The viewport width in NextJS does not extend across the entire screen on mobile devices

I'm currently tackling a challenge with my NextJS Website project. It's the first time this issue has arisen for me. Typically, I set the body width to 100% or 100vw and everything works smoothly. However, upon switching to a mobile device, I not ...

Receiving an `Invalid module name in augmentation` error is a common issue when using the DefaultTheme in Material

After following the guidelines outlined in the migration documentation (v4 to v5), I have implemented the changes in my theme: import { createTheme, Theme } from '@mui/material/styles' import { grey } from '@mui/material/colors' declar ...

Intellisense for dispatch types in Redux Toolkit

After following the documentation for redux toolkit with typescript, I implemented my own useDispatch hook as shown below export const useAppDispatch = () => useDispatch<AppDispatch>() and used it in components like this const dispatch = useAppDi ...

Wait for a minimum of X milliseconds using RxJS

I'm attempting to achieve a specific functionality using RxJS: Trigger an event Make an API call Upon receiving the API response, do one of the following: Wait for at least X milliseconds after triggering the event If X milliseconds have already p ...