73

I am getting error in this implementation of typescript code. I am mapping here one type to another. But vscode shows error that variable 'test' is used before being assigned. can anyone please help?

interface A {
   name: string;
   age: string;
   sex: string;
}

interface B {
   name: any;
   age: string;
   sex: string;
 }

const modifyData = (g : B) :A => {

    let test: A;
    test.name = g.name['ru'];
    test.age = g.age;
    test.sex = g.sex;

   return test as A;
};

const g = [{
  "name": {
      "en": "George",
      "ru": "Gregor"
       },
  "age": "21",
  "sex": "Male"
},
{
  "name": {
      "en": "David",
      "ru": "Diva"
       },,
  "age": "31",
  "sex": "Male"
}];

const data = g.map(modifyData);
console.log(data);
dhruv2204
  • 832
  • 1
  • 6
  • 10

3 Answers3

105

To clarify a little, this hinges on the difference between "assigned" and "defined." For example:

let myDate: Date; // I've defined my variable as of `Date` type, but it still has no value.

if (!someVariable) {
   myDate = new Date();
}

console.log(`My date is ${myDate}`) // TS will throw an error, because, if the `if` statement doesn't run, `myDate` is defined, but not assigned (i.e., still has no actual value).
   

Defining simply means giving it an initial value:

let myDate: Date | undefined = undefined; // myDate is now equal to `undefined`, so whatever happens later, TS won't worry that it won't exist.

Andrew
  • 3,825
  • 4
  • 30
  • 44
  • 14
    Yes thanks, this was my issue. You don't need to explicitly assign undefined - TS just needs to know it is expected: `let myDate: Date | undefined;` – theisof Feb 18 '21 at 10:56
81

The error is triggered because typescript sees the variable still as undefined in some scenarios. Adding !before variable tells typescript to remove undefined or null as possibles types for variable:

let test!: A;

Definite assignment assertions doc

Playground: typescript/playground

TOPKAT
  • 6,667
  • 2
  • 44
  • 72
princekin
  • 835
  • 4
  • 2
  • 17
    the answer may be useful, but it's not at least for me. A brief explanation of what ! means here, would be very convenient – d.k Oct 13 '21 at 16:09
  • 10
    The main idea here is that Typescript calculates all possible scenarios, even the ones which are not so obvious at first glance, thus its inference ability encounters a possible `null` or `undefined` type. So if you are certain that certain variable actually will not be `null` or `undefined`, you may hint TS by postfix `!`, which simply removes `null` and `undefined` from the type of an expression. [More info](https://stackoverflow.com/a/47704683/6423716) – ogostos Oct 26 '21 at 09:49
  • 4
    Another way to put it is the ! operator means you want to tell the compiler that you know best. You are asserting that the value will always be specified. It's rare that you should need to do this as it's easy to get caught out at runtime. – Ross Coundon Dec 04 '21 at 22:06
  • 4
    It's called Definite Assignment Assertions: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite-assignment-assertions – cprcrack Apr 22 '22 at 08:50
  • This is gold, many thanks @princekin. In my case, the variable is being assigned in a try/catch block but needs to be defined outside the block so that I can return the result if it does not fail. – martinp999 Sep 05 '22 at 00:33
18

It is indeed unassigned. It is defined, but it has no value.

In my humble opinion, the cleanest way would be to return a literal:

const modifyData = (g: B):A => {
    return {
        name: g.name['ru'],
        age: g.age,
        sex: g.sex
    } as A;
};
Kevinvhengst
  • 1,672
  • 4
  • 27
  • 40
mleko
  • 11,650
  • 6
  • 50
  • 71