1

This code gives me "Type 'string' is not assignable to type 'never'" where the comment is made.

type serviceInfoType = {
    PORT: number;
    HOST: string;
    MS_NAME: string;
    MS_KEY: string;
};
type serviceInfoParametersType = keyof serviceInfoType;
let serviceInfo = {} as serviceInfoType;
let serviceInfoParameters: Array<serviceInfoParametersType> = [
    "PORT",
    "HOST",
    "MS_NAME",
    "MS_KEY",
];
serviceInfoParameters.forEach((e) => {
    // Type 'string' is not assignable to type 'never'
    serviceInfo[e] = 'something';
});

If I change the code to this:

serviceInfo[e as string] = 'something';

Then it works. But I have no idea why it doesn't work. Can anyone explain why it says type never?

EDIT:

Alex Kolarski made a right call of me trying to assign .env variables (which types I changed).

You can do this (which works and is correct way):

if (e === "PORT") serviceInfo[e] = process.env[e];
else if (e === "MICROSERVICE_NAME") serviceInfo[e] = process.env[e];
else serviceInfo[e] = process.env[e];

Which is "essentially" this:

serviceInfo[e] = process.env[e];

Except this doesn't work.

If you don't need anything else but to assign values you are OK with the 'as string' hack. But if you need to do other stuff like changing or checking types of the variables, you should use the correct way. Because then the intellisense works and TS is happy.

2
  • 5
    This sets PORT to the value "something", a string, but that property's type is declared as number. So you get an error message because the code is logically wrong. For an explanation of the "type never" part, see this Q&A. Commented Jan 9, 2023 at 21:35
  • @kaya3 I made the code simpler. I know i can't assign "something" to number. But thanks for the link. Commented Jan 9, 2023 at 21:50

1 Answer 1

1

The error happens because TypeScript does not know the type of serviceInfo[e].

If e = "PORT" the type of serviceInfo[e] is number

If e = NOT "PORT" the type of serviceInfo[e] is string

So the type of serviceInfo[e] becomes never since it cannot be both string and number at the same time.

So when you have serviceInfo[e] = 'something', TypeScript it is not sure how to type check it, because you are trying to assign a string ("something") to serviceInfo[e] that can be either string and number and in the case if it is a number there should be an error.

serviceInfo["PORT"] = 'something'; - you are assigning string to a number.


There are several ways to mitigate this.

Option 1: Make sure serviceInfo[e] is only one type the type in the forEach like so:

serviceInfoParameters.forEach((e) => {
    if (e === "PORT") {
        serviceInfo[e] = 3000;
    } else {
        serviceInfo[e] = 'something';
    }
});

This way TypeScript will figure out that if e is not "PORT" it always defaults to a string.

Option 2 (not ideal): You can make everything in serviceInfoType a string like so:

type serviceInfoType = {
    PORT: string;
    HOST: string;
    MS_NAME: string;
    MS_KEY: string;
};

Then you will have no issues.

I'm not sure of the goal here, so I cannot provide more context, but it seems to me that you are trying to load .env file and in that case it make sense that everything should be a string and type it that way.

Then you can convert it if you need a number.

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

4 Comments

Thank you for commenting, I added EDIT to my question and upvoted your answer.
Yeah, all env variables by definition are strings. So the cleanest way for me is to create a type RawEnvVariables like so: type RawEnvVariables = Record<string, string> and assign your env variables. And then if you wish you can parse it to your custom interface EnvVariables where you use parseInt(..,10) to convert the env variables to your interface. const env: EnvVariables = {...myRawVars, PORT: parseInt(myRawVars['PORT'], 10)};
I have changed the types of these variables in .d.ts like so: declare global { namespace NodeJS { interface ProcessEnv { ... }}} . Because I didn't want to do this checking and parsing. Which works fine.
Another note: doing serviceInfo[e as string] = 'something'; is problematic and can cause you troubles in other cases. In this case since it is a const it might be ok. serviceInfo["PORT"] is a number for typescript, but in reality is a string. Doing serviceInfo["PORT"] + 1 typescript will think that it is adding numbers, but you will be doing concatenation.

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.